最近在思考一个问题。在线服务器运行各种服务。可能这个运行nginx,那个运行mysql,其他的运行nfs或者其他服务等等。有些服务是用一定的脚本编写的,用来监控所有服务器的进程占用情况。如果该服务器运行的服务不在固定列表中,则监控服务无法获取相应的数据。
为了解决这个问题,我最近在想zabbix的自动发现功能是否可以自动发现占用服务器内存最大的N个进程,然后监控这些进程的内存和CPU资源来获取数据。于是这篇文章诞生了。
首先,我们需要得到最高指挥部的结果。您可以使用以下命令将top命令获得的结果重定向到一个文件:
top -b -n 1 >/tmp/top.txt该命令意味着执行一次top命令,并将结果重定向到top.txt文件。
将该命令添加到zabbix用户的预定任务中,每分钟执行一次。该命令如下所示:
crontab -e */1 * * * * top -b -n 1 >/tmp/top.txt放进去之后,会在tmp目录下生成一个top.txt文件。
$ 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资源的信息。让我们先看看第一个脚本:
$ 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(Kina)printa[K]/1024,K}'|sort-gr|head-10|cut-d""-f2`这个命令:这个命令的意思是从top.txt文件中取出第八行到最后一行的数据,然后用awk累加这些数据。效果是以最后一列为关键字,累加每个关键字对应的第六列的值,输出第六列和最后一列的累加结果。然后用sort排序。注意,这里的参数是-gr而不是-nr,因为第六列的值以KB为单位。如果一个进程占用的内存超过10G,它将使用科学记数法进行计数。sort-nr参数不能计算科学记数法,所以需要将参数改为-gr,其中-r是反向排序。同时,为了防止zabbix得到的值被科学记数法识别,先将值/1024改为MB,然后在zabbix得到数据后*1024*1024将值恢复为BYTE。Head-10就是把占用内存最多的十个进程拿出来,然后对数据进行切割,得到这十个进程的进程名。至于下面的代码,是json格式化得到的十个进程名的输出,输出结果如下:
$ 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格式化的值才可以识别。
第二个脚本的作用是获取某个进程占用的cpu和内存资源。该脚本的内容如下:
$ 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使配置生效,需要使用pkillzabbix&zabbix-2.4.4/sbin/zabbix_agentd
==========================================================================================
==========================================================================================
==========================================================================================
不好意思,上面用====框起来的代码有问题。经过博主的提醒,我已经发现问题了。top命令中,内存占用单位默认为KB,但当某个进程占用大量内存时,其单位就会变成MB甚至GB,甚至TB。目前无法通过awk得到正确的值(不好意思,我水平有限,但是对不起aww所以,今天我用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端配置模板。
在配置-模板-创建模板中创建一个模板,名为templetop_process,如下图所示:
创建一个名为“进程资源顶部”的应用程序集,如下图所示:
在创建之后,我们需要添加发现规则,这是我们的亮点。创建新的发现规则,如下图所示:
的键值是我们在客户端上配置的键值。我把数据更新间隔设置为5分钟,也就是说每隔5分钟它就会去客户端获取占用内存最多的十个进程,然后取它们的内存和cpu资源数据。现在您需要配置项目原型,如下图所示:
如上图所示,{#TABLENAME}获取十个进程名的列表,process.resource[{#tablename},mem]是我们在客户端配置的键值,其中获取的内存值单位为MB。这里转换成字节单位,所以获取的值*1024*1024=1048576,单位改为字节,这样应用到项目中,一个项目原型就成功了。以下是cpu占用资源的原型配置:
添加项目原型后,需要配置图形原型,如下图所示:
添加图形原型后,模板更改成功。接下来,将模板添加到主机,就可以获取数据了。这里,因为我设置的自动发现时间间隔是5分钟,所以在图形出现之前,我需要等待5分钟以上。这是出现的图形效果。
这是内存占用量最大的十个进程的资源占用图。下面是详细效果。
这是新获得的数据。至此,通过自动发现对top10进程占用资源的监控结束。这只是我自己匆忙写的一个监控方法。拿出来供大家参考。如果有更好的办法,可以和我一起探讨,共同进步。我会把zabbix模板放在附件里供你下载。
由于参数略有变化,模板文件也略有修改。我将把修改后的模板文件上传到附件中。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)