如何查看 jvm 实际使用的内存数量jvm jstat 监控

Zabbix使用自动发现功能监控服务器各JVM进程状态_服务器应用_Linux公社-Linux系统门户网站
你好,游客
Zabbix使用自动发现功能监控服务器各JVM进程状态
来源:Linux社区&
作者:gfbhfdgf
前言==========为什么需要做服务器jvm自动发现的监控呢?这个事情主要有两点原因:& & 1.zabbix默认监控jvm状态是使用jmx中转进行监控的,监控效率比较低下& & 2.zabbix使用jmx监控jvm的时候由于一个主机上的键值不能重复,也就导致了一台主机上只能监控一个jvm实例& & 以上两点原因导致zabbix通过jmx监控jvm的实现不是很理想,加上最近老大要求收集服务器上面跑的所有java应用的信息,于是自己琢磨了下,还是自己动手,丰衣足食。利用了周末的时间,通过使用shell脚本+java工具jstat+zabbix实现监控主机上多jvm实例的功能。第一章:概念的理解&首先,既然要监控jvm状态,那就必须要了解jvm里面的信息,楼主通过搜索资料加自动脑补,把网上的资料取其精华,去其糟粕,整理了一下。JVM中的内存分类分为堆内存和非堆内存,堆内存是给实际应用使用的,非堆内存是给jvm容器使用的。我们主要关心的是堆内存这块。在堆内存里面,给内存分为如下几块:&1.Young代(年轻代)&2.Old代(老年代)&3.Perm代(永久代)(关于这一点,在JDK7和JDK8中情况不一样,将在后面进行分析)&其中,年轻代里面又分成了三块,如下:&1.Eden代(伊甸园代)&2.survivor0代(0号幸存区)&3.survivor1代(1号幸存区)&至于更详细的关于JVM堆内存的信息,各位可以自行百度或者google,我这里就不赘述了,毕竟我也是个半桶水,自己找了点资料外加脑补到的一些东西,不敢在关公门前耍大刀了。&当然,还得科普一个东西,那就是GC,所谓的GC就是JVM在运行的时候会有一个垃圾回收机制,这个垃圾回收机制是什么情况呢?就是在程序运行的时候会产生很多已经不使用的空间,但还是被占用了的情况,这样会造成很多不必要的浪费,于是JVM就有一个垃圾回收机制,针对程序中已经不使用的内存资源,会进行回收释放,这个过程就叫做GC。当然,关于GC还有很多内容我这里也没有详述,理由同上条。各位看官只需要知道GC是JVM监控里面的一个很重要的参数就行了。&第一章,关于JVM中概念的理解结束了,预知后事如何,请听下回分解。第二章:JAVA工具的选用&java工具有很多,关于jvm监控的工具主要有如下几个:&+ jstat&+ jmap&+ jstack&其中jmap --heap pid可以抓出挺多的关于某个jvm的运行参数,但是老大提醒我最好不要使用jmap进行jvm监控,具体没有说明原因。于是本着打破砂锅问到底的精神,我又去搜了一把,发现了如下内容:&jmap最主要的危险操作是下面这三种: 1. jmap -dump 这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。2. jmap -permstat 这个命令执行,JVM会去统计perm区的状况,这整个过程也会比较的耗时,并且同样也会暂停应用。3. jmap -histo:live 这个命令执行,JVM会先触发gc,然后再统计信息。上面的这三个操作都将对应用的执行产生影响,所以建议如果不是很有必要的话,不要去执行。所以,从上面三点来看,jmap命令对jvm状态影响还是比较大的,而且执行jmap --heap的时间也比较长,效率较低,予以排除。接下来是jstack,这个命令可以深入到JVM里面对JVM运行问题进行排查,据说还可以统计JVM里面的线程数量。但是这个命令执行效率也比较低,被排除掉了。于是剩下的只有一个jstat命令了。下面来详细的讲解该命令的使用了,咳咳,各位快点打起点精神来,这可是重头戏来了。首先,列出jstat命令的一些使用案例吧:============================================ 1.jstat -gc pid & & & & & & 可以显示gc的信息,查看gc的次数,及时间。 & & & & & & 其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。 S0C& & S1C& & S0U& & S1U& & & EC& & & EU& & & & OC& & & & OU& & & PC& & PU& & YGC& & YGCT& & FGC& & FGCT& & GCT& & 48.0& 0.0& 048.0 & & &
& & 317& & 4.850& 4& & & 0.971& & 5.821 &S0C& & S1C& & S0U& & S1U& & & EC& & & EU& & & & OC& & & & OU& & & MC& & MU& & CCSC& CCSU& YGC& & YGCT& & FGC& & FGCT& & GCT& & 4.0& 0.0& 320.0& 604.6& & & 42.6 3.1& & 2& & & 0.128& 24.138 2.jstat -gccapacity pid & & & & & & 可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小, & & & & & & 如 PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量, & & & & & & PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。 & & & & & & 其他的可以根据这个类推, OC是old内纯的占用量。 &NGCMN& & NGCMX& & NGC& & S0C& S1C& & & EC& & & OGCMN& & & OGCMX& & & OGC& & & & OC& & & PGCMN& & PGCMX& & PGC& & & PC& & YGC& & FGC& &144.0
48.0 & & & &
& & 317& & 4 &NGCMN& & NGCMX& & NGC& & S0C& S1C& & & EC& & & OGCMN& & & OGCMX& & & OGC& & & & OC& & & MCMN& & MCMX& & & MC& & CCSMN& & CCSMX& & CCSC& & YGC& & FGC& &592.0& 2.0& 512.0& 0608.0& & & 0.0 & 39344.0& & & 0.0 & 74& & 2 3.jstat -gcutil pid & & & & & & 统计gc信息统计。 & S0& & S1& & E& & & O& & & P& & YGC& & YGCT& & FGC& & FGCT& & GCT& & & 0.00& 51.19& 83.29& 65.44& 61.41& & 317& & 4.850& & 4& & 0.971& & 5.821 & & & S0& & S1& & E& & & O& & & M& & CCS& & YGC& & YGCT& & FGC& & FGCT& & GCT& & &68.75& 0.00& 46.74& 57.47& 96.95& 95.03& & & 2& & 0.128& 24.143 4.jstat -gcnew pid & & & & & 年轻代对象的信息。 &S0C& & S1C& & S0U& & S1U& TT MTT& DSS& & & EC& & & EU& & YGC& & YGCT& 48.0& & 0.0 & 15 048.0 & & 317& & 4.850 &S0C& & S1C& & S0U& & S1U& TT MTT& DSS& & & EC& & & EU& & YGC& & YGCT& &512.0& 512.0& 352.0& & 0.0 15& 15& 512.0& 46.4&
5.jstat -gcnewcapacity pid & & & & & 年轻代对象的信息及其占用量。 NGCMN& & & NGCMX& & & NGC& & & S0CMX& & S0C& & S1CMX& & S1C& & & ECMX& & & & EC& & & YGC& FGC& & 360.0& 360.0& 7& & 4 NGCMN& & & NGCMX& & & NGC& & & S0CMX& & S0C& & S1CMX& & S1C& & & ECMX& & & & EC& & & YGC& FGC& & 4592.0& & 856.0& & 512.0& 57856.0& & 512.0& & & 75& & 2 6.jstat -gcold pid & & & & & old代对象的信息。 & PC& & & PU& & & & OC& & & & & OU& & & YGC& & FGC& & FGCT& & GCT& &
& & & & & & 317& & 4& & 0.971& & 5.821 & MC& & & MU& & & CCSC& & CCSU& & & OC& & & & & OU& & & YGC& & FGC& & FGCT& & GCT& & &142.6& 03.1& & & & & 5475& & 2& & 0.128& 24.148 7.jstat -gcoldcapacity pid & & & & & old代对象的信息及其占用量。 & OGCMN& & & OGCMX& & & & OGC& & & & OC& & & YGC& FGC& & FGCT& & GCT& & & & & & & & & & 317& & 4& & 0.971& & 5.821 & OGCMN& & & OGCMX& & & & OGC& & & & OC& & & YGC& FGC& & FGCT& & GCT& & & & & & & & & & 5475& & 2& & 0.128& 24.148 & & & & 8.jstat -gcpermcapacity pid & & & & & perm对象的信息及其占用量。 & PGCMN& & & PGCMX& & & PGC& & & & PC& & & YGC& FGC& & FGCT& & GCT& & & & & & & 317& & 4& & 0.971& & 5.821 没有 9.jstat -class pid & & & & & 显示加载class的数量,及所占空间等信息。 Loaded& Bytes& Unloaded& Bytes& & Time& & &.7& & .1& & & 15.19 Loaded& Bytes& Unloaded& Bytes& & Time& & & .0& & & & 0& & 0.0& & & 5.97 10.jstat -compiler pid & & & & & 显示VM实时编译的数量等信息。 Compiled Failed Invalid& Time& FailedType FailedMethod & & 4219& & & 3& & & 0& & 63.36& & & & & 1 org/aspectj/weaver/ResolvedType addAndRecurse Compiled Failed Invalid& Time& FailedType FailedMethod & 11364& & & 1& & & 0& 107.53& & & & & 1 sun/nio/cs/UTF_8$Decoder decode 11.stat -printcompilation pid & & & & & 当前VM执行的信息。 Compiled& Size& Type Method & & & & 1 net/spy/memcached/protocol/ascii/BaseGetOpImpl initialize Compiled& Size& Type Method & 11364& & 212& & 1 com/alibaba/rocketmq/client/impl/consumer/RebalanceService run & ==================================================
& 可以看出上面我列出的命令执行结果为什么有两行呢,这是因为是用不同的jdk版本执行的。& 上面是JDK7执行结果,下面是JDK8执行结果,这两个版本之间输出的结果是有差距的,下面,就来分析为什么会产生这种差异。JDK7和JDK8中JVM堆内存划分差异& 如果记性好的童鞋们应该还能记得我上面在介绍JVM堆内存分类的时候括号里写的那个东东吧,没错,就是这个东西导致的。在JDK7中的Perm代(永久代)在JDK8中被废除了,取而代之的是Metadata代(元数据代),据说这个元数据代相对于永久代进行了优化,如果不设置最大值的话,默认会按需增长, 不会造成像Perm代中内存占满后会爆出内存溢出的错误,元数据代也可以设置最大值,这样的话,当内存区域被消耗完的时候将会和Perm代一样爆出内存溢出的错误。(PS:原谅我的班门弄斧,只能解释到这一个层面了。)好了,解释清楚了JDK7和JDK8的差异以后,接下来我们来解释jstat抓到的这些参数了。960 jstat命令获取参数解析 ====================================================================================== * S0C 年轻代中第一个survivor(幸存区)的容量 (字节)jstat -gcnew $pid|tail -1|awk '{print $1*1024}'* S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (字节)jstat -gcnew $pid|tail -1|awk '{print $3*1024}'* S0 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比jstat -gcutil $pid|tail -1|awk '{print $1}'* S0CMX 年轻代中第一个survivor(幸存区)的最大容量 (字节)jstat -gcnewcapacity $pid|tail -1|awk '{print $4*1024}'*& * S1C 年轻代中第二个survivor(幸存区)的容量 (字节)jstat -gcnew $pid|tail -1|awk '{print $2*1024}'* S1U 年轻代中第二个survivor(幸存区)目前已使用空间 (字节)jstat -gcnew $pid|tail -1|awk '{print $4*1024}'* S1 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比jstat -gcutil $pid|tail -1|awk '{print $2}'* S1CMX& 年轻代中第二个survivor(幸存区)的最大容量 (字节)jstat -gcnewcapacity $pid|tail -1|awk '{print $6*1024}'* DSS 当前需要survivor(幸存区)的容量 (字节)(Eden区已满)jstat -gcnew $pid|tail -1|awk '{print $7*1024}'*& * EC 年轻代中Eden(伊甸园)的容量 (字节)jstat -gcnew $pid|tail -1|awk '{print $8*1024}'* EU 年轻代中Eden(伊甸园)目前已使用空间 (字节)jstat -gcnew $pid|tail -1|awk '{print $9*1024}'* ECMX 年轻代中Eden(伊甸园)的最大容量 (字节)jstat -gcnewcapacity $pid|tail -1|awk '{print $8*1024}'* E 年轻代中Eden(伊甸园)已使用的占当前容量百分比jstat -gcutil $pid|tail -1|awk '{print $3}'*& * NGCMN 年轻代(young)中初始化(最小)的大小 (字节)jstat -gccapacity $pid|tail -1|awk '{print $1*1024}'* NGCMX 年轻代(young)的最大容量 (字节)jstat -gccapacity $pid|tail -1|awk '{print $2*1024}'* NGC 年轻代(young)中当前的容量 (字节)jstat -gccapacity $pid|tail -1|awk '{print $3*1024}'*& * OC Old代的容量 (字节)jstat -gcold $pid|tail -1|awk '{print $3*1024}'* OU Old代目前已使用空间 (字节)jstat -gcold $pid|tail -1|awk '{print $4*1024}'* OGCMX old代的最大容量 (字节)jstat -gccapacity $pid|tail -1|awk '{print $8*1024}'* OGCMN old代中初始化(最小)的大小 (字节)jstat -gccapacity $pid|tail -1|awk '{print $7*1024}'* O old代已使用的占当前容量百分比jstat -gcutil $pid|tail -1|awk '{print $4}'* OGC old代当前新生成的容量 (字节)jstat -gccapacity $pid|tail -1|awk '{print $9*1024}'*& * PC Perm(持久代)的容量 (字节)jstat -gccapacity $pid|tail -1|awk '{print $14*1024}'* PU Perm(持久代)目前已使用空间 (字节)jstat -gc $pid|tail -1|awk '{print $10*1024}'* PGCMX perm代的最大容量 (字节)jstat -gccapacity $pid|tail -1|awk '{print $12*1024}'* PGCMN perm代中初始化(最小)的大小 (字节)jstat -gccapacity $pid|tail -1|awk '{print $11*1024}'* P perm代已使用的占当前容量百分比 jstat -gcutil $pid|tail -1|awk '{print $5*1024}'* PGC perm代当前新生成的容量 (字节)jstat -gccapacity $pid|tail -1|awk '{print $13*1024}'*& * YGC 从应用程序启动到采样时年轻代中gc次数jstat -gccapacity $pid|tail -1|awk '{print $15}'* YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)jstat -gcutil $pid|tail -1|awk '{print $7}'* FGC从应用程序启动到采样时old代(全gc)gc次数jstat -gccapacity $pid|tail -1|awk '{print $16}'* FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)jstat -gcutil $pid|tail -1|awk '{print $9}'* GCT 从应用程序启动到采样时gc用的总时间(s)jstat -gcutil $pid|tail -1|awk '{print $10}'*& * TT& 持有次数限制jstat -gcnew $pid|tail -1|awk '{print $5}'* MTT& 最大持有次数限制jstat -gcnew $pid|tail -1|awk '{print $6}'* * Loadedjvm加载class数量 * Unloadedjvm未加载class数量 * * M元数据区使用比例 * MC当前元数据空间大小 * MU元数据空间使用大小 * MCMN最小元数据容量& * MCMX最大元数据容量 *& * CCS压缩使用比例 * CCSC当前压缩类空间大小 * CCSU压缩类空间使用大小 * CCSMN最小压缩类空间大小 * CCSMX最大压缩类空间大小 ====================================================
好了,上面就是我找到的一些对jstat获取的数据意思的统计,各位看官可以做个参考。好了,这一章的内容到此基本结束,前面的东西都是一些理论类的东西,没有实际的操作。俗话说,光说不练假把式。接下来,我们将开启下一章的旅程,脚本+jstat的使用。第三章:脚本+jstat获取数据首先,我们来看一下该章节介绍的几个脚本吧:1.jvm_list.sh 获取该机器上所有运行的JVM的进程对应的程序根目录以及程序名称2.get_jvmlist.sh 将获取的该机器上的所有进程对应的程序名称序列化成json格式并发送给zabbix服务器3.get_jvmstatus.sh 通过获取的程序根目录获取到对应的程序进程,再通过jstat抓取数据写入到文件中缓存4.set_jvmstatus.sh zabbix通过调用该脚本获取缓存文件中的关于某个JVM进程的状态信息好了,简单介绍了上面几个脚本的功能,下面我们列出这几个脚本的实际内容:& & #cat jvm_list.sh& & & #!/bin/bash & & & & & packagePath=/usr/local/etc/scripts/package_path.txt & & echo -n &$packagePath & & & & & for i in `ps -fC java|tail -n +2|grep -v 'flume'|awk '{print $2}'`; & & do& & & & & & pgrootpath=`ls -l /proc/$i/cwd|awk '{print $NF}'` & & & & & & if [[ -r $pgrootpath/appconfig ]] && [& `grep ^packagename= $pgrootpath/appconfig|wc -l`==1 ];then& & & & & & & & & & & & & & packagename=$(grep ^packagename= $pgrootpath/appconfig 2&/dev/null|awk -F'"' '{print $2}') & & & & & & elif [[ -r $pgrootpath/webconfig ]] && [& `grep ^packagename= $pgrootpath/webconfig|wc -l`==1 ];then& & & & & & & & & & & & & & packagename=$(grep ^packagename= $pgrootpath/webconfig 2&/dev/null|awk -F'"' '{print $2}') & & & & & & else& & & & & & & & & & packagename=$(basename $pgrootpath)-1.0.0-bin.tar.gz & & & & & & fi& & & & & & & & & echo "$packagename $pgrootpath" && $packagePath & & done
该脚本的目的是先通过使用ps -fC java命令获取该机器上面除了flume进程外的所有其他java进程(我这边使用的是flume来收集业务日志的。)然后,通过获取到的PID使用ll /proc/pid/cwd命令获取该进程的程序根目录,后面那些判断是获取该进程对应的包名(这一步各位可以根据自己公司的情况自行修改,我这边取包名的方式并不能够匹配各位公司的设置,在下爱莫能助了。)最后是将获取到的程序根目录和包名存放在变量packagePath对应的文件中。& & #cat get_jvmlist.sh& & & #!/bin/bash & & & & & TABLESPACE=`awk '{print $1}' /usr/local/etc/scripts/package_path.txt` & & 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 ']}'
这个脚本的作用就是通过读取文件里面的包名,然后将包名进行json序列化输出,没什么好讲的,套路套一个循环脚本就行。接下来就是重要的脚本了,调用jstat获取JVM状态,并缓存到文件中。#cat get_jvmstatus.sh& & & #!/bin/bash & & & & & MAINCLASS="*Main.class"& & scriptPath=/usr/local/etc/scripts& & & & & cat $scriptPath/package_path.txt|while read line & & do& & packageName=$(echo $line|awk '{print $1}') & & pgRootPath=$(echo $line|awk '{print $2}') & & if [[ -d $pgRootPath/tomcat ]];then& & pid=$(cat $pgRootPath/tomcat/tomcat.pid) & & else& & mainPath=$(find $pgRootPath -name $MAINCLASS) & & appName=$(echo ${mainPath##*classes/}|sed 's#/#.#g'|sed 's#.class##g') & & pid=$(ps -fC java|grep "$appName"|awk '{print $2}') & & fi& & javaHome=/usr/local/java/jdk1.8.0 & & #javaHome=/usr/local/java/latest & & #if [[ -r $pgRootPath/appconfig ]] && [& `grep ^JAVA_HOME= $pgRootPath/appconfig|wc -l` == 1 ] && [ `grep ^JAVA_HOME= $pgRootPath/appconfig|grep 8|wc -l` == 1 ];then & & & & & & & & & & & & & & #javaHome=$(grep ^JAVA_HOME= $pgRootPath/appconfig 2&/dev/null|awk -F'=' '{print $2}') & & #javaHome=/usr/local/java/jdk1.8.0 & & & & & & #else & & & & & & #& & & & if [[ -r $pgRootPath/webconfig ]] && [ `grep ^'export JAVA_HOME=' $pgRootPath/webconfig|wc -l` == 1 ] && [ `grep ^'export JAVA_HOME=' $pgRootPath/webconfig|grep 8|wc -l` == 1 ];then & & & & & & #& & & & & & & & #javaHome=$(grep ^'export JAVA_HOME=' $pgRootPath/webconfig 2&/dev/null|awk -F'"' '{print $2}') & & & & & & #& & & & javaHome=/usr/local/java/jdk1.8.0 & & #fi & & #fi & & #echo --------------------------------$pgRootPath & & #echo $javaHome & & echo -------------------------------$pid & & sleep 5 & & #echo -n &$scriptPath/package/$packageName & & #$javaHome/bin/jstat -gccapacity $pid & ./package/$packageName 2&/dev/null & & #$javaHome/bin/jmap -heap $pid&&./package/$packageName 2&/dev/null & & echo gcnew && $scriptPath/package/$packageName 2&/dev/null& & $javaHome/bin/jstat -gcnew $pid && $scriptPath/package/$packageName 2&/dev/null& & echo gcutil && $scriptPath/package/$packageName 2&/dev/null& & $javaHome/bin/jstat -gcutil $pid && $scriptPath/package/$packageName 2&/dev/null& & echo gcnewcapacity && $scriptPath/package/$packageName 2&/dev/null& & $javaHome/bin/jstat -gcnewcapacity $pid && $scriptPath/package/$packageName 2&/dev/null& & & & & & echo gccapacity && $scriptPath/package/$packageName 2&/dev/null& & $javaHome/bin/jstat -gccapacity $pid && $scriptPath/package/$packageName 2&/dev/null& & & & & & #echo gcold && $scriptPath/package/$packageName 2&/dev/null & & #$javaHome/bin/jstat -gcold $pid && $scriptPath/package/$packageName 2&/dev/null & & & & & & echo gc && $scriptPath/package/$packageName 2&/dev/null& & $javaHome/bin/jstat -gc $pid && $scriptPath/package/$packageName 2&/dev/null& & & & & & echo class && $scriptPath/package/$packageName 2&/dev/null& & $javaHome/bin/jstat -class $pid && $scriptPath/package/$packageName 2&/dev/null& & echo cpu && $scriptPath/package/$packageName 2&/dev/null& & echo -e "CPU\n$( ps aux|grep $pid|grep -v grep|awk '{print $3}')" && $scriptPath/package/$packageName 2&/dev/null& & echo mem && $scriptPath/package/$packageName 2&/dev/null& & echo -e "MEM\n$( ps aux|grep $pid|grep -v grep|awk '{print $6}')" && $scriptPath/package/$packageName 2&/dev/null& & & & & done
这里面首先是通过获取到程序的根目录,然后我这的java程序除了tomcat跑的之外,其他的java程序都是通过Main.class启动的,所以可以获取到AppName,这样通过ps命令就能找到其对应的PID了,而如果是tomcat启动的进程的话,在程序根目录下面的tomcat目录下有一个tomcat.pid文件里面有该程序的PID。后面被注释的那一端代码其实之前是加上去的,那段代码的作用是判断该进程使用的是JDK7还是JDK8启动的,当初的计划是想着如果是JDK7启动的进程就用JDK7的jstat去获取数据,如果是JDK8启动的进程就用JDK8的jstat去获取数据,后来发现不同版本的JDK获取的数据格式不同,于是。。。。。。后悔莫及的把那段代码注释掉了。后面综合公司实际情况考虑,JDK8的程序用得比较多,JDK7的程序相对来说比较少,并且慢慢都会向JDK8进行转换,所以,权衡利弊之下,之后将jstat的JDK全部换成了JDK8,这样的影响就是获取不到JDK7的永久代数据。当然,各位有兴趣的话,也可以JDK7和JDK8同时使用,在过滤输出文件的时候加一个标志位进行判断,当然,我这里暂时没有做这方面的修改。。。毕竟时间有限。。。第四个脚本,个人感觉写的最烂的一个脚本。。。但是。。。没办法,技术水平有限,各位将就着看吧(捂脸哭)# cat set_jvmstatus.sh& & & #!/bin/bash & & packageName=$1 & & key=$2 & & & & & if [ $2 == "S0C" -o $2 == "S0U" -o $2 == "S1C" -o $2 == "S1U" -o $2 == "DSS" -o $2 == "EC" -o $2 == "EU" ];then& & part=gcnew & & elif [ $2 == "S0" -o $2 == "S1" -o $2 == "E" -o $2 == "O" -o $2 == "M" -o $2 == "CCS" -o $2 == "YGCT" -o $2 == "FGCT" -o $2 == "GCT" ];then& & part=gcutil & & elif [ $2 == "S0CMX" -o $2 == "S1CMX" -o $2 == "ECMX" ];then& & part=gcnewcapacity & & elif [ $2 == "NGCMN" -o $2 == "NGCMX" -o $2 == "NGC" -o $2 == "OGCMX" -o $2 == "OGCMN" -o $2 == "OGC" -o $2 == "MCMN" -o $2 == "MCMX" -o $2 == "MC" -o $2 == "CCSMN" -o $2 == "CCSMX" -o $2 == "CCSC" -o $2 == "YGC" -o $2 == "FGC" ];then& & part=gccapacity & & elif [ $2 == "MU" -o $2 == "CCSU" -o $2 == "OC" -o $2 == "OU" ];then& & part=gc & & elif [ $2 == "Loaded" -o $2 == "Unloaded" ];then& & part=class & & elif [ $2 == "CPU" ];then& & part=cpu & & elif [ $2 == "MEM" ];then& & & & & & part=mem & & else& & echo "Error input:"& & exit 0 & & fi& & case $2 in& & S0C) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $1*1024}'& & ;; & & S0U) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $3*1024}'& & ;; & & S0) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $0}'& & ;; & & S0CMX) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $4*1024}'& & ;; & & S1C) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $2*1024}'& & ;; & & S1U) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $4*1024}'& & ;; & & S1) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $2}'& & ;; & & S1CMX) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $6*1024}'& & ;; & & DSS) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $7*1024}'& & ;; & & EC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $8*1024}'& & ;; & & EU) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $9*1024}'& & ;; & & ECMX) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $8*1024}'& & ;; & & E) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $3}'& & ;; & & NGCMN) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $1*1024}'& & ;; & & NGCMX) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $2*1024}'& & ;; & & NGC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $3*1024}'& & ;; & & OC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $7*1024}'& & ;; & & OU) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $8*1024}'& & ;; & & OGCMX) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $8*1024}'& & ;; & & OGCMN) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $7*1024}'& & ;; & & O) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $4}'& & ;; & & OGC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $9*1024}'& & ;; & & M) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $5}'& & ;; & & MC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $13*1024}'& & ;; & & MU) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $10*1024}'& & ;; & & MCMN) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $11*1024}'& & ;; & & MCMX) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $12*1024}'& & ;; & & CCS) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $6}'& & ;; & & CCSC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $13*1024}'& & ;; & & CCSU) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $12*1024}'& & ;; & & CCSMN) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $14*1024}'& & ;; & & CCSMX) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $15*1024}'& & ;; & & YGC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $17}'& & ;; & & YGCT) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $8}'& & ;; & & FGC) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $18}'& & ;; & & FGCT) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $10}'& & ;; & & GCT) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $11}'& & ;; & & TT) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $5}'& & ;; & & MTT) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $6}'& & ;; & & Loaded) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $1}'& & ;; & & Unloaded) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $3}'& & ;; & & CPU) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%f\n", $1}'& & ;; & & MEM) & & grep -wA 2 ^"$part" /usr/local/etc/scripts/package/$1|tail -1|awk '{printf "%d\n", $1*1024}'& & ;; & & *) & & echo "Error input:"& & ;; & & esac& & exit 0
这套脚本没什么讲的,就是重复的进行一些判断,抓数据并输出(注意,之前写的获取的jstat参数的值其实是不准确的,获取的值是以KB为单位而不是以字节为单位,所以我取完数据后对数据进行成字节为单位了。)接下来,讲一下这几个脚本该怎么部署。我这里的zabbix_agentd是通过yum安装的,所以安装在/usr/local目录下,配置文件在/usr/local/etc目录下,需要在zabbix_agentd.conf里面添加下面两行获取数据的key(注意,添加好后一定要记得重启zabbix_agentd进程):UserParameter=jmx.discovery,/usr/local/etc/scripts/get_jvmlist.sh UserParameter=jmx.resource[*],/usr/local/etc/scripts/set_jvmstatus.sh $1 $2
然后脚本都放置在/usr/local/etc/scripts/目录下,该目录下的脚本权限如下:&-rwxr-xr-x 1 zabbix zabbix& 326 3月& 26 22:29 get_jvmlist.sh &-rwxr-xr-x 1 root& root& 2956 3月& 28 20:57 get_jvmstatus.sh &-rwxr-xr-x 1 root& root& & 818 3月& 26 22:33 jvm_list.sh &drwxr-xr-x 2 zabbix zabbix 4096 3月& 26 23:05 package &-rw-r--r-- 1 zabbix zabbix 1947 3月& 29 11:23 package_path.txt &-rwxr-xr-x 1 zabbix zabbix 5240 3月& 28 20:50 set_jvmstatus.sh
然后需要在crontab里面定义jvm_list.sh和get_jvmstatus.sh脚本的定时任务,我这里定义的如下:12 * */1 * * * /usr/local/etc/scripts/jvm_list.sh */5 * * * * /usr/local/etc/scripts/get_jvmstatus.sh
注意这两个脚本必须要以root权限去执行,因为里面涉及到的一些命令只有root用户才有权限去执行。之后可以手动执行脚本去获取数据,看是否能够抓取到相应的数据。好了,这章的脚本讲完了,下一章,就是怎样通过zabbix获取相应的数据了。第四章:zabbix获取数据
通过之前的脚本部署,可以在zabbix_server上面通过zabbix_get命令去检查是否获取到了相应的数据:
& & # zabbix_get& -s xx.xx.xx.xx -k jmx.resource[Abcdefg-1.0.0-rc-bin.tar.gz,MEM]& & 我这里可以获取到数据了(注意IP被我注释掉了,为了保护隐私哈,包名也被我刻意修改了,隐私隐私哈)接下来就可以部署模板了,至于模板我已经做好了,可以直接在附件里面下载。至于模板我制作了一些简单的key的值收集,以及图像的展示,至于监控报警值的设置,由于各个公司的环境不一样,需要各位自己根据自己需求自行设置。
Zabbix模板到Linux公社资源站下载:
------------------------------------------分割线------------------------------------------
免费下载地址在
用户名与密码都是
具体下载目录在 /2016年资料/9月/12日/Zabbix使用自动发现功能监控服务器各JVM进程状态/
下载方法见
------------------------------------------分割线------------------------------------------
本文永久更新链接地址:
相关资讯 & & &
& (09月20日)
& (08月23日)
& (09月15日)
& (08月18日)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款}

我要回帖

更多关于 jvm jstat 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信