最近在想一個問題,線上服務器跑的服務五花八門,可能這臺跑的是nginx,另外一臺跑的是mysql,其餘的跑的是nfs或者其餘服務等等,經過某一個腳本中固定的寫入一些服務來實現監控全部的服務器的進程佔用資源狀況佔用zabbix服務器資源不說,假如該服務器跑的服務不在固定列表中,監控服務獲取不到相應數據。
java
爲了解決這個問題,最近在想經過zabbix的自動發現功能能不能實現自動發現佔用服務器內存最大的N個進程,而後對這些進程佔用內存和CPU的資源狀況進行監控獲取數據呢?因而就有了本篇文章的誕生。
python
首先,咱們須要獲取到top命令結果,能夠使用下面的命令將top命令獲取的結果重定向到一個文件中去:mysql
top -b -n 1 >/tmp/top.txt
其中該命令的意思是執行一次top命令並將結果重定向到top.txt文件中去nginx
將該命令添加到zabbix用戶的計劃任務中去,每分鐘執行一次,命令以下:web
crontab -e */1 * * * * top -b -n 1 >/tmp/top.txt
放進去以後在tmp目錄下會生成一個top.txt文件sql
# head -10 /tmp/top.txt top - 15:42:01 up 72 days, 22:25, 2 users, load average: 0.09, 0.08, 0.06 Tasks: 880 total, 1 running, 879 sleeping, 0 stopped, 0 zombie %Cpu(s): 2.8 us, 0.7 sy, 0.0 ni, 96.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 13175284+total, 97396048 free, 20357148 used, 13999640 buff/cache KiB Swap: 32767996 total, 32452380 free, 315616 used. 11058964+avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 20732 zabbix 20 0 130716 2436 1204 R 11.8 0.0 0:00.03 top 126808 upload 20 0 8375636 945876 27268 S 5.9 0.7 63:33.97 java 127591 upload 20 0 9898.1m 1.078g 27960 S 5.9 0.9 63:58.01 java
好了,獲取到了數據後,就須要對數據進行處理了,下面是兩個腳本,一個是爲了獲取佔用內存資源最高的進程名,另外一個是獲取某進程佔用內存和cpu資源的信息。先來看第一個腳本:docker
# cat scripts/check_process.sh #!/bin/bash TABLESPACE=`tail -n +8 /tmp/top.txt|awk '{a[$NF]+=$6}END{for(k in a)print a[k]/1024,k}'|sort -gr|head -10|cut -d" " -f2` COUNT=`echo "$TABLESPACE" |wc -l` INDEX=0 echo '{"data":[' echo "$TABLESPACE" | while read LINE; do echo -n '{"{#TABLENAME}":"'$LINE'"}' INDEX=`expr $INDEX + 1` if [ $INDEX -lt $COUNT ]; then echo ',' fi done echo ']}'
其中最關鍵的是`tail -n +8 /tmp/top.txt|awk '{a[$NF]+=$6}END{for(k in a)print a[k]/1024,k}'|sort -gr|head -10|cut -d" " -f2`這條命令:這條命令的意思是從top.txt文件中取出從第八行到末尾行的數據,而後使用awk對這些數據進行累加,效果是以最後一列爲關鍵字,每一個關鍵字對應的第6列的數值進行累加,輸出第六列數據的累加結果和最後一列數據,而後使用sort進行排序,注意這裏的參數是使用-gr而不是使用-nr是由於獲取到的第六列的值是以KB爲單位的,假如某進程佔用內存大於10G的話,將會使用科學記數法計數,sort -nr參數沒法對科學記數法進行計數,須要將參數改爲-gr才行,其中的-r是進行反向排序,同時爲了防止zabbix獲取到該值是科學記數法獲取的值從而沒法識別,先將該值/1024將單位變成MB,當zabbix獲取到數據後再*1024*1024將該值還原成BYTE單位。head -10是取出佔用內存最大的十個進程,而後使用cut對數據進行切分,得到十個進程的進程名。至於下面的代碼是將獲取到的十個進程名進行json格式化的輸出,輸出結果以下:shell
$ sh ./scripts/check_process.sh {"data":[ {"{#TABLENAME}":"java"}, {"{#TABLENAME}":"docker"}, {"{#TABLENAME}":"nginx"}, {"{#TABLENAME}":"sshd"}, {"{#TABLENAME}":"tuned"}, {"{#TABLENAME}":"NetworkMa+"}, {"{#TABLENAME}":"zabbix_ag+"}, {"{#TABLENAME}":"systemd-j+"}, {"{#TABLENAME}":"crond"}, {"{#TABLENAME}":"rsyslogd"}]}
至於爲啥要進行json格式化,是由於zabbix自動發現獲取的值格式就是json格式化的值才能被識別到。
json
第二個腳本的做用就是獲取某個進程佔用的cpu和內存資源狀況,腳本內容以下:bash
$ cat ./scripts/processmonitor.sh #!/bin/bash process=$1 name=$2 case $2 in mem) echo "`tail -n +8 /tmp/top.txt|awk '{a[$NF]+=$6}END{for(k in a)print a[k]/1024,k}'|grep "$process"|cut -d" " -f1`" ;; cpu) echo "`tail -n +8 /tmp/top.txt|awk '{a[$NF]+=$9}END{for(k in a)print a[k],k}'|grep "$process"|cut -d" " -f1`" ;; *) echo "Error input:" ;; esac exit 0
該腳本的核心和上一個腳本的很類似,相信讀者理解了上面的腳本在理解下面的腳本也是輕輕鬆鬆的啦。下面看該腳本執行的結果:
$ sh ./scripts/processmonitor.sh java mem 13115.5 $ sh ./scripts/processmonitor.sh java cpu 17.7
能獲取到值了以後就須要在zabbix_agentd.conf裏面配置相應的鍵值來獲取數據了,下面是須要添加的配置:
$ tail -3 ./etc/zabbix_agentd.conf #top_process UserParameter=process.discovery,/home/zabbix/zabbix-2.4.4/scripts/check_process.sh UserParameter=process.resource[*],/home/zabbix/zabbix-2.4.4/scripts/processmonitor.sh $1 $2
添加該配置以後須要重啓zabbix_agentd才能使配置生效,
重啓須要使用pkill zabbix && zabbix-2.4.4/sbin/zabbix_agentd
=======================================================================================================
抱歉,上面用====框住的這段代碼存在問題,通過博友們的提醒,我已經發現問題的所在了,在top命令中內存的佔用單位默認是KB,可是當某個進程佔用內存比較大時,其單位將會變成MB甚至是GB,乃至TB,目前來講我經過awk沒法獲取到正確的數值(抱歉,本人水平有限,對AWK使用還欠缺火候),因而,本人今天使用python實現了上面框住部分的代碼,下面貼出本人使用python寫出的腳本:
$ cat process.py #!/usr/bin/env python # -*- coding: utf-8 -*- # author: huxianglin #date:2015-09-11 import string import sys def read_line(line): line = line.strip('\n').strip() programname = line.split()[11] memoryuse = line.split()[5] cpuuse = line.split()[8] return programname,memoryuse,cpuuse def getdate(file_path): with open(file_path) as f: for line in range(1,8): next(f) result=[] for line in f: result.append(list(read_line(line))) return result def topprogram(file_path): date=getdate(file_path) top={} for i in date: if 't' in i[1]: i[1]=string.atof(i[1].split('t')[0])*1073741824 elif 'g' in i[1]: i[1]=string.atof(i[1].split('g')[0])*1048576 elif 'm' in i[1]: i[1]=string.atof(i[1].split('m')[0])*1024 else: i[1]=string.atof(i[1]) if top.get(i[0]): top[i[0]]=[top[i[0]][0]+i[1],top[i[0]][1]+string.atof(i[2])] else: top.setdefault(i[0],[i[1],string.atof(i[2])]) return sorted(top.items(),key=lambda d:d[1][0])[-1:-11:-1] def translatejson(file_path): data=topprogram(file_path) print'{"data":[' for i in data: if i != data[-1]: print '{"{#TABLENAME}":"%s"},' %i[0] else: print '{"{#TABLENAME}":"%s"}]}' %i[0] def printdata(file_path,key): data=topprogram(file_path) for i in data: if key[1] == 'cpu': if key[0] == i[0]: print i[1][1] else: if key[0] == i[0]: print i[1][0] def main(): file_path='/tmp/top.txt' if sys.argv[1] == 'json': translatejson(file_path) else: key = [sys.argv[1],sys.argv[2]] printdata(file_path,key) if __name__=='__main__': main()
使用上面的python代碼輸入的參數稍微有點改變,下面是使用效果:
$ ./process.py json {"data":[ {"{#TABLENAME}":"java"}, {"{#TABLENAME}":"haproxy"}, {"{#TABLENAME}":"docker"}, {"{#TABLENAME}":"nginx"}, {"{#TABLENAME}":"sshd"}, {"{#TABLENAME}":"systemd-j+"}, {"{#TABLENAME}":"bash"}, {"{#TABLENAME}":"rsyslogd"}, {"{#TABLENAME}":"tuned"}, {"{#TABLENAME}":"NetworkMa+"}]} [zabbix@dev01 scripts]$ ./process.py java mem 36773689.408 [zabbix@dev01 scripts]$ ./process.py java cpu 77.9
這上面獲取到的纔是服務器真實資源佔用的數據,以前的shell腳本做廢了。因爲腳本傳入參數進行了改變,因而在zabbix_agentd.conf中得參數也得修改成以下形式:
$ tail -3 /home/zabbix/zabbix-2.4.4/etc/zabbix_agentd.conf #top_process UserParameter=process.discovery[*],/home/zabbix/zabbix-2.4.4/scripts/process.py $1 UserParameter=process.resource[*],/home/zabbix/zabbix-2.4.4/scripts/process.py $1 $2
好了,這樣,客戶端這邊就已經配置成功了,下面須要在服務端驗證是否可以獲取到數據了,在服務端使用zabbix_get命令來獲取數據,下面是執行的結果:
$ zabbix/bin/zabbix_get -s xxx.xxx.xxx.xxx -k"process.discovery[json]" {"data":[ {"{#TABLENAME}":"java"}, {"{#TABLENAME}":"docker"}, {"{#TABLENAME}":"nginx"}, {"{#TABLENAME}":"sshd"}, {"{#TABLENAME}":"tuned"}, {"{#TABLENAME}":"NetworkMa+"}, {"{#TABLENAME}":"zabbix_ag+"}, {"{#TABLENAME}":"systemd-j+"}, {"{#TABLENAME}":"rsyslogd"}, {"{#TABLENAME}":"bash"}]}
面的xxx.xxx.xxx.xxx表明的是客戶端的IP地址,-k後面的參數就是剛剛咱們在客戶端上面添加的參數。
$ zabbix/bin/zabbix_get -s xxx.xxx.xxx.xxx -k"process.resource[java,mem]" 13115.6 $ zabbix/bin/zabbix_get -s xxx.xxx.xxx.xxx -k"process.resource[java,cpu]" 0
好了,在服務端測試客戶端沒有問題,可以獲取到數據了。接下來就須要在web端配置模板了。
在組態---》模板---》建立模板裏面建立一個模板,叫作temple top_process以下圖所示:
建立一個應用集叫作top of process resource,以下圖所示:
建立好後,須要添加探索規則了,這是咱們的重頭戲。新建探索規則,以下圖所示:
其中的鍵值就是咱們在客戶端上面配置的鍵值,數據更新間隔我這裏設置爲5分鐘,就是說每間隔5分鐘它就會去客戶端獲取佔用內存最大的十個進程,而後取它們的內存和cpu佔用資源數據。下面就須要配置項目原型了,以下圖所示:
如上圖所示,{#TABLENAME}獲取的就是十個進程名的列表,process.resource[{#TABLENAME},mem]就是咱們在客戶端配置的鍵值,其中獲取的內存數值單位是MB,這裏將它轉換成BYTE單位,因此將獲取到的數值*1024*1024=1048576,單位改爲Byte,將該項目應用到top of process resourceying應用集上。這樣,一個項目原型就作成功了。下面是cpu佔用資源的項目原型配置:
添加好圖形原形後,改模版就製做成功了,接下來將該模板添加到主機上,就可以獲取到數據了,這裏由於我設置的自動發現時間間隔是5分鐘,因此須要等待五分鐘以上纔會出現圖形,下面是出現的圖形效果。
這就是獲取到的十個佔用內存最大的進程的佔用資源圖形,下面是詳細效果。
這是剛獲取到的數據,至此,經過自動發現獲取top10進程佔用資源的監控結束,這只是本人匆忙之中寫出的一個監控方式,拿出來給你們做參考,若是有更好的方式,能夠和我共同探討,你們共同進步,zabbix模板我將會放在附件中供你們下載。