JavaWeb的監控系統
第一部分:實時系統監控(cpu利用率,cpu溫度,總記憶體大小,已使用記憶體大小)
第二部分:實時告警
由於無重新整理實時性,所以只能使用Ajax,這裡沒有用到任何ajax框架,因為呼叫比較簡單
大家知道,由於java的先天不足,對底層系統的呼叫和操作一般用jni來完成,特別是cpu溫度,你在window下是打死用命令列是得不到的,但由於我們的伺服器系統是linux,所以可以不呼叫jni完全用java的方式來得到系統資訊,這裡用到了runtime的exec()函式,通過解析本地命令呼叫的結果來查詢本地資訊,
這裡要感謝公司同事qinkun推薦ecsun兄的這篇文章http://papa.iteye.com/blog/220532,
- * 取得linux系統下的cpu、記憶體資訊
- *
- * */
- public final class LinuxSystemTool
- {
- /**
- * get memory by used info
- *
- * @return int[] result
- * result.length==4;int[0]=MemTotal;int[1]=MemFree;int[2]=SwapTotal;int[3]=SwapFree;
- * @throws IOException
- * @throws InterruptedException
- */
- public static int[] getMemInfo() throws IOException, InterruptedException
- {
- File file = new File("/proc/meminfo");
- BufferedReader br = new BufferedReader(new InputStreamReader(
- new FileInputStream(file)));
- int[] result = new int[4];
- String str = null;
- StringTokenizer token = null;
- while((str = br.readLine()) != null)
- {
- token = new StringTokenizer(str);
- if(!token.hasMoreTokens())
- continue;
- str = token.nextToken();
- if(!token.hasMoreTokens())
- continue;
- if(str.equalsIgnoreCase("MemTotal:"))
- result[0] = Integer.parseInt(token.nextToken());
- else if(str.equalsIgnoreCase("MemFree:"))
- result[1] = Integer.parseInt(token.nextToken());
- else if(str.equalsIgnoreCase("SwapTotal:"))
- result[2] = Integer.parseInt(token.nextToken());
- else if(str.equalsIgnoreCase("SwapFree:"))
- result[3] = Integer.parseInt(token.nextToken());
- }
- return result;
- }
- /**
- * get memory by used info
- *
- * @return float efficiency
- * @throws IOException
- * @throws InterruptedException
- */
- public static float getCpuInfo() throws IOException, InterruptedException
- {
- File file = new File("/proc/stat");
- BufferedReader br = new BufferedReader(new InputStreamReader(
- new FileInputStream(file)));
- StringTokenizer token = new StringTokenizer(br.readLine());
- token.nextToken();
- int user1 = Integer.parseInt(token.nextToken());
- int nice1 = Integer.parseInt(token.nextToken());
- int sys1 = Integer.parseInt(token.nextToken());
- int idle1 = Integer.parseInt(token.nextToken());
- Thread.sleep(1000);
- br = new BufferedReader(
- new InputStreamReader(new FileInputStream(file)));
- token = new StringTokenizer(br.readLine());
- token.nextToken();
- int user2 = Integer.parseInt(token.nextToken());
- int nice2 = Integer.parseInt(token.nextToken());
- int sys2 = Integer.parseInt(token.nextToken());
- int idle2 = Integer.parseInt(token.nextToken());
- return (float)((user2 + sys2 + nice2) - (user1 + sys1 + nice1)) / (float)((user2 + nice2 + sys2 + idle2) - (user1 + nice1 + sys1 + idle1));
- }
- }
這裡的兩個方法,解釋一下,
方法1檔案"/proc/meminfo"裡面包含的就是記憶體的資訊,還包括了swap的資訊。例如:
$ cat /proc/meminfo
total: used: free: shared: buffers: cached:
Mem: 1057009664 851668992 205340672 0 67616768 367820800
Swap: 2146787328 164429824 1982357504
MemTotal: 1032236 kB
MemFree: 200528 kB
MemShared: 0 kB
這樣可以用擷取字串的方法,來得到linux記憶體資訊.
方法2在檔案"/proc/stat"裡面就包含了CPU的資訊。每一個CPU的每一tick用在什麼地方都在這個檔案裡面記著。後面的數字含義分別是: user、nice、sys、idle、iowait。有些版本的kernel沒有iowait這一項。這些數值表示從開機到現在,CPU的每tick用在了哪裡。例如:
cpu0 256279030 0 11832528 1637168262
就是cpu0從開機到現在有 256279030 tick用在了user消耗,11832528用在了sys消耗。所以如果想計算單位時間(例如1s)裡面CPU的負載,那隻需要計算1秒前後數值的差除以每一秒的tick數量就可以了。
ok這樣還剩下cpu溫度,怎麼做呢
發現了一個檔案"cat /proc/acpi/thermal_zone/THM/temperature";可以返回本機的linux溫度,
大概是這樣的:temperature: 68C
但不是每臺linux機器都有這個THM你要確定你的linux載入了這個THM才能使用這個檔案,這樣就用InputStreamReader(new FileInputStream(new File("/proc/acpi/thermal_zone/THM/temperature")),去讀取這個檔案,後面的相信大家一定會做了吧,就是把內容讀出來,然後分割字串去得到這個68。ok,系統基本資訊全部完成,然後ok現在就只有一件事就是用Ajax去呼叫這個類來得到 基本資訊,然後返回到頁面上,Ajax的用法就不贅言了。
下面是系統監控的效果,大概是Ajax每幾秒去linux下去取一次系統資訊,然後顯示在jsp頁面上,以下是效果。
到這裡第一部分系統監控部分已經完成,現在開始完成實時告警部分,分析需求
1溫度和cpu超過額定值需要告警
2使用者作業系統失敗,使用者儲存空間不足也需要告警,還有我們公司的業務操作失敗告警,如果發生Exception也只能告警,當然要把異常的堆疊的資訊儲存在資料庫裡,我就這樣設計如果使用者在操作中觸發了這些錯誤,則儲存在資料庫的告警表裡,然後實時監控的再取出來這些資訊。
3告警是要實時的那麼要怎麼從告警表裡查到當前以後的資料呢,一開始想到用當前時間,在當前時間加上Ajax傳送時間間隔,select * from warnlist where date>new Date()+AjaxTime這種形式,後來發現時間是很不正確的,網路延遲,程式處理時間,(cpu資訊用了sleep函式),等等你常常會發現有些告警資訊被無情的放過,而有的時候有重複資料,這樣我想到了用id,每次進入告警系統先查詢到最大的告警id,然後儲存在session中,然後ajax從資料庫裡取告警資訊的時候都查這個id之後的資料(就是進入監控系統後的最新資料),然後session再儲存新的最大id,下次ajax取還是從這個session中取最大id,這樣資訊就可以當ajax取的時候都保證是最新的,而且沒有重複,very good!就這樣做了
這樣設計了一張告警處理表
- CREATE TABLE `warnlist` (
- `Id` bigint(20) NOT NULL auto_increment,
- `warnleave` tinyint(2) NOT NULL default '0',//告警級別:告警的嚴重程度
- `fromguy` varchar(20) NOT NULL,//屬於哪個使用者哪個組織的告警
- `warncontent` varchar(100) NOT NULL,//告警內容,比如cpu使用率超過80%
- `aviliablevalue` varchar(12) default NULL,//允許值 比如85%
- `warnvalue` varchar(12) default NULL,//告警值 80
- `warntime` datetime NOT NULL,//告警時間
- `stackinfo` varchar(255) default NULL,//異常的堆疊資訊
- `dealwith` tinyint(2) NOT NULL default '0',//處理結果
- `version` int(11) default NULL,//version
- `organizerID` varchar(20) default NULL,//組織id
- `des` varchar(255) default NULL,
- PRIMARY KEY (`Id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
假設我ajax從系統取資訊後,那麼要寫個邏輯,if(cpuTempature>75C)or if(cpuUserd>80%)則寫入資料庫,然後再查詢大於上一次傳送Ajax資料庫的最大id的告警資訊(這期間如果發生的以下錯誤一併查出:使用者儲存空間不足,還有我們公司的業務操作失敗告警,Exception等),迴圈插入一個xml解析類中,大概形式是這樣的Ajax返回這個xml,供頁面提取資訊
- <response>
- <cpuUsed>67</cpuUsed>
- <cpuTemp>76<cpuTemp>
- <Memory>1023422</Memory>
- <freeMemory>43244</freeMemory>
- <wannlist>
- <warnid>2</warnid>
- <warncontent>系統儲存空間不足</warncontent>
- <fromguy>kakaluyi</fromguy>
- ..............
- </wanrlist>
- <warnlist>
- <warnid>3</warnid>
- <warncontent>cpu溫度過高</warncontent>
- <fromguy>系統</fromguy>
- <orgid>系統</orgid>
- <warnvalue>78</warnvalue>
- .............
- </warnlist>
- ........
- </response>
系統資訊的顯示程式碼,就是關聯上面那個圖片的:
- var cpuUsed=req.responseXML.getElementsByTagName('cpuUsed')[0].firstChild.nodeValue;
- var totalMemory=req.responseXML.getElementsByTagName('totalMemory')[0].firstChild.nodeValue;
- var freeMemory=req.responseXML.getElementsByTagName('freeMemory')[0].firstChild.nodeValue;
- var cpuTemp=req.responseXML.getElementsByTagName('cpuTemp')[0].firstChild.nodeValue;
- $('cpuUsed').innerHTML=cpuUsed;
- $('totalMemory').innerHTML=totalMemory;
- $('freeMemory').innerHTML=freeMemory;
- $('cpuTemp').innerHTML=cpuTemp;
- //jsp
- <tr>
- <td class="label" width="20%">
- 伺服器CPU使用率:</td>
- <td class="text">
- <font color="#FF0000" size="+2"><label id="cpuUsed"></label>
- </font> < 告警預定閥值: 80% >
- </td>
- </tr>
- .........
然後就是頁面展現的問題了這裡我用了dom節點的增刪,一個頁面保持50條記錄,如果超過50條則刪除以前的節點,程式碼為:
- var length=req.responseXML.getElementsByTagName('warnlist').length;
- if(length>0)
- {
- var trlength=document.getElementsByTagName('table')[4].childNodes[0].childNodes.length;
- if(trlength+length-1>50)//如果大於50條,則查詢告警列表的table,得到
- 告警資訊的子節點,然後刪除多餘的最早的告警資訊
- {
- var tbody=document.getElementsByTagName('table')[4].childNodes[0];
- for(var i=1;i<trlength+length-50;i++)
- {
- var tr=tbody.childNodes[i];
- tr.parentNode.removeChild(tr);
- }
然後插入新的告警資訊,
- for(var i=0;i<length;i++)
- {
- var onewarnlist=req.responseXML.getElementsByTagName('warnlist')[i].childNodes;
- if(onewarnlist[0].firstChild.nodeValue==0)
- {
- var leave="企業級告警";
- }
- else {
- var leave="運營商級告警";
- }
- var from=onewarnlist[1].firstChild.nodeValue;
- var warncontent=onewarnlist[2].firstChild.nodeValue;
- var aviliablevalue=onewarnlist[3].firstChild.nodeValue;
- var warnvalue=onewarnlist[4].firstChild.nodeValue;
- var warntime=onewarnlist[5].firstChild.nodeValue;
- var id=onewarnlist[8].firstChild.nodeValue;
- if(onewarnlist[6].firstChild.nodeValue==0)
- {
- var dealwith="未處理" ;
- }
- else {
- var dealwith="<font color='red'>已處理</font>";
- }
- var table=document.getElementById('warntable');
- var tr=document.createElement('tr');
- if(x%2==1)
- {
- tr.style.backgroundColor="#BFD3F9"
- }
- else{
- tr.style.backgroundColor="#FBFCEB"
- }
- x++;
- table.appendChild(tr);
- var td=document.createElement('td');
- td.className ='listText';
- td.innerHTML =x;
- tr.appendChild(td);
- var td1=document.createElement('td');
- td1.className ='listText';
- td1.innerHTML = leave;
- tr.appendChild(td1);
- var td2=document.createElement('td');
- td2.className ='listText';
- td2.innerHTML = from;
- tr.appendChild(td2);
- var td3=document.createElement('td');
- td3.className ='listText';
- td3.innerHTML = warncontent;
- tr.appendChild(td3);6
- var td4=document.createElement('td');
- td4.className ='listText';
- td4.innerHTML = aviliablevalue;
- tr.appendChild(td4);
- var td5=document.createElement('td');
- td5.className ='listText';
- td5.innerHTML = '<font color="#FF0000">'+warnvalue+'</font>';
- tr.appendChild(td5);
- var td6=document.createElement('td');
- td6.className ='listText';
- td6.innerHTML = warntime;
- tr.appendChild(td6);
- var td7=document.createElement('td');
- td7.className ='listText';
- td7.innerHTML = dealwith;
- tr.appendChild(td7);
- var td8=document.createElement('td');
- td8.className ='listText';
- td8.innerHTML = id;
- tr.appendChild(td8);
- }
ok,一切大功告成,以下是最終效果
相關文章
- Mysql 監控系統MySql
- 監控系統元件元件
- 運維監控系統 PIGOSS BSM的監控策略運維Go
- 實時監控系統,統一監控企業APIAPI
- Mac系統監控工具Mac
- 打造前端監控系統前端
- 手刃前端監控系統前端
- Cacti 監控 AIX 系統AI
- 智慧工地監控系統
- 智慧影片監控系統
- 監控linux系統的shellLinux
- 一種對雲主機進行效能監控的監控系統及其監控方法
- 系統監控&JVM監控指標資料查詢JVM指標
- 視訊監控系統的設計
- 什麼才算好的監控系統?
- EUROCAT-X的OASYS監控系統
- Domino Mail 系統的多級監控AI
- 駕駛員監控系統(DMS)
- python搭建系統監控Python
- sysstat——系統效能監控神器
- Docker 容器監控系統初探Docker
- Prometheus監控報警系統Prometheus
- 直播間截留監控系統
- zabbix系統監控部署(上)
- fanotify 監控檔案系統
- Nagios監控系統搭建iOS
- AIX系統nmon工具監控AI
- 搭建完美的監控系統
- linux 系統監控工具Linux
- 電力影片監控系統
- 影片監控智慧分析系統
- Linux 系統監控指南Linux
- 影片監控ai分析系統AI
- 蘋果系統用於系統監控和管理的命令蘋果
- 分散式監控系統Zabbix-新增windows監控主機分散式Windows
- 基於 Prometheus 的監控系統實踐Prometheus
- 轉轉支付通道監控系統的搭建
- zabbix監控系統的安裝與配置