首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現 Linux 服務器監控系統:實時指標採集、異常告警與 Ajax 前端展示

     編輯:Java 相關知識

系統架構設計

基於 Linux /proc 虛擬文件系統採集指標,後端 Servlet 提供數據,前端 Ajax 輪詢渲染,支持 CPU、內存、溫度監控及業務異常告警。

一、核心指標採集工具類

public final class LinuxSystemTool {
    /** 讀取 /proc/meminfo 解析內存信息
     * @return int[4] = {MemTotal, MemFree, SwapTotal, SwapFree} (單位 KB) */
    public static int[] getMemInfo() throws IOException, InterruptedException {
        File file = new File("/proc/meminfo");
        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
            int[] result = new int[4];
            String line;
            while ((line = br.readLine()) != null) {
                StringTokenizer st = new StringTokenizer(line);
                if (!st.hasMoreTokens()) continue;
                String key = st.nextToken();
                if (!st.hasMoreTokens()) continue;
                int val = Integer.parseInt(st.nextToken());
                switch (key) {
                    case "MemTotal:": result[0] = val; break;
                    case "MemFree:":  result[1] = val; break;
                    case "SwapTotal:": result[2] = val; break;
                    case "SwapFree:":  result[3] = val; break;
                }
            }
            return result;
        }
    }

    /** 計算 CPU 使用率(採樣間隔 1 秒)
     * @return 0.0~1.0 之間的浮點數 */
    public static float getCpuInfo() throws IOException, InterruptedException {
        File file = new File("/proc/stat");
        long[] t1 = readCpuLine(file);
        Thread.sleep(1000);
        long[] t2 = readCpuLine(file);
        
        long userDiff = t2[0] - t1[0];
        long niceDiff = t2[1] - t1[1];
        long sysDiff  = t2[2] - t1[2];
        long idleDiff = t2[3] - t1[3];
        long totalDiff = userDiff + niceDiff + sysDiff + idleDiff;
        
        return (float)(userDiff + niceDiff + sysDiff) / totalDiff;
    }

    private static long[] readCpuLine(File file) throws IOException {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            st.nextToken(); // 跳過 "cpu"
            return new long[]{
                Long.parseLong(st.nextToken()), // user
                Long.parseLong(st.nextToken()), // nice
                Long.parseLong(st.nextToken()), // sys
                Long.parseLong(st.nextToken())  // idle
            };
        }
    }

    /** 讀取 CPU 溫度(需內核支持 thermal_zone) */
    public static int getCpuTemp() throws IOException {
        File file = new File("/proc/acpi/thermal_zone/THM/temperature");
        if (!file.exists()) return -1; // 不支持
        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
            String line = br.readLine(); // 格式: "temperature: 68 C"
            return Integer.parseInt(line.split(":")[1].trim().replace("C", ""));
        }
    }
}

二、異常告警持久化設計

1. 數據庫表結構

CREATE TABLE warnlist (
    Id BIGINT PRIMARY KEY AUTO_INCREMENT,
    warnleave TINYINT DEFAULT 0,        -- 0:企業級 1:運營商級
    fromguy VARCHAR(20) NOT NULL,       -- 告警來源用戶/組織
    warncontent VARCHAR(100) NOT NULL,  -- 告警內容
    aviliablevalue VARCHAR(12),         -- 閾值
    warnvalue VARCHAR(12),              -- 實際值
    warntime DATETIME NOT NULL,         -- 告警時間
    stackinfo VARCHAR(255),             -- 異常堆棧
    dealwith TINYINT DEFAULT 0,         -- 0:未處理 1:已處理
    organizerID VARCHAR(20),            -- 組織ID
    des VARCHAR(255)                    -- 描述
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2. 告警觸發邏輯(後端定時任務)

// 伪代碼:每分鐘執行
if (cpuTemp > 75 || cpuUsage > 0.8) {
    insertWarn("系統", "CPU溫度/使用率過高", "75/80%", String.valueOf(cpuTemp));
}
if (diskUsage > 0.9) {
    insertWarn("系統", "磁盤空間不足", "90%", String.valueOf(diskUsage));
}
// 業務異常捕獲點統一調用
catch (Exception e) {
    insertWarn(user, "業務異常", "", "", e.getStackTraceAsString());
}

三、前端 Ajax 輪詢與增量告警獲取

1. 會話級最大 ID 追蹤策略

避免時間戳不準導致漏報/重複:

  • 頁面加載時查詢 MAX(Id) 存入 Session
  • 每次 Ajax 請求攜帶 lastMaxId,後端查 WHERE Id > ?
  • 返回新數據後更新 Session 中的最大 ID

2. XML 響應格式

<response>
  <cpuUsed>67</cpuUsed>
  <cpuTemp>76</cpuTemp>
  <totalMemory>1023422</totalMemory>
  <freeMemory>43244</freeMemory>
  <warnlist>
    <warnid>2</warnid>
    <warncontent>系統存儲空間不足</warncontent>
    <fromguy>kakaluyi</fromguy>
    ...
  </warnlist>
  <warnlist>...</warnlist>
</response>

3. 前端 DOM 更新(保留最近 50 條)

var warns = req.responseXML.getElementsByTagName('warnlist');
var table = document.getElementById('warntable');
var tbody = table.tBodies[0];
var currentRows = tbody.rows.length;

// 刪除超出 50 條的舊行
if (currentRows + warns.length > 50) {
    var removeCount = currentRows + warns.length - 50;
    for (var i = 0; i < removeCount; i++) {
        tbody.deleteRow(1); // 保留表頭第0行
    }
}

// 追加新行
for (var i = 0; i < warns.length; i++) {
    var w = warns[i];
    var row = tbody.insertRow(-1);
    row.style.backgroundColor = (totalRows++ % 2) ? "#BFD3F9" : "#FBFCEB";
    
    var cells = [
        totalRows,
        w.getElementsByTagName('warnleave')[0].textContent == '0' ? '企業級告警' : '運營商級告警',
        w.getElementsByTagName('fromguy')[0].textContent,
        w.getElementsByTagName('warncontent')[0].textContent,
        w.getElementsByTagName('aviliablevalue')[0].textContent,
        '' + w.getElementsByTagName('warnvalue')[0].textContent + '',
        w.getElementsByTagName('warntime')[0].textContent,
        w.getElementsByTagName('dealwith')[0].textContent == '0' ? '未處理' : '已處理',
        w.getElementsByTagName('warnid')[0].textContent
    ];
    cells.forEach((text, idx) => {
        var cell = row.insertCell(idx);
        cell.className = 'listText';
        cell.innerHTML = text;
    });
}

四、關鍵技術點總結

  1. /proc 文件系統:Linux 內核暴露的運行時信息接口,無需 JNI 即可讀取
  2. CPU 使用率計算:兩次採樣差值法,公式 (user+nice+sys)_diff / total_diff
  3. 告警去重:基於遞增 ID 的增量拉取,比時間戳更可靠
  4. 前端性能:限制 DOM 節點數量,使用 deleteRow/insertRow 原生操作

此架構可輕鬆擴展至多服務器集群監控,只需在採集端部署 Agent 並上報中心庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved