zabbix使用自動發現功能監控服務器各JVM進程狀態

前言java

==========web

爲何須要作服務器jvm自動發現的監控呢?這個事情主要有兩點緣由:shell

    1.zabbix默認監控jvm狀態是使用jmx中轉進行監控的,監控效率比較低下json

    2.zabbix使用jmx監控jvm的時候因爲一個主機上的鍵值不能重複,也就致使了一臺主機上只能監控一個jvm實例緩存

    以上兩點緣由致使zabbix經過jmx監控jvm的實現不是很理想,加上最近老大要求收集服務器上面跑的全部java應用的信息,因而本身琢磨了下,仍是本身動手,豐衣足食。利用了週末的時間,經過使用shell腳本+java工具jstat+zabbix實現監控主機上多jvm實例的功能。tomcat

第一章:概念的理解bash

 首先,既然要監控jvm狀態,那就必需要了解jvm裏面的信息,樓主經過搜索資料加自動腦補,把網上的資料取其精華,去其糟粕,整理了一下。JVM中的內存分類分爲堆內存和非堆內存,堆內存是給實際應用使用的,非堆內存是給jvm容器使用的。咱們主要關心的是堆內存這塊。在堆內存裏面,給內存分爲以下幾塊:服務器

 1.Young代(年輕代)併發

 2.Old代(老年代)app

 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   
9792.0 10048.0  0.0   5143.2 242048.0 220095.4  323200.0   211509.3  186368.0 114451.6    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   
1024.0 1024.0  0.0   320.0  11776.0  11604.6   260608.0   149759.6  39344.0 38142.6 4528.0 4303.1   5473   24.010   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 
 87360.0 262144.0 262144.0 9792.0 10048.0 242048.0   174784.0   786432.0   323200.0   323200.0 131072.0 262144.0 186368.0 186368.0    317     4
 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC 
 1536.0 174592.0  13312.0  512.0  512.0  11776.0   260608.0   349696.0   260608.0   260608.0      0.0 1083392.0  39344.0      0.0 1048576.0   4528.0   5474     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   5474   24.014     2    0.128   24.143
4.jstat -gcnew pid
           年輕代對象的信息。
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
9792.0 10048.0    0.0 5143.2  3  15 9792.0 242048.0 198653.2    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  11776.0   8446.4   5474   24.014
5.jstat -gcnewcapacity pid
           年輕代對象的信息及其佔用量。
NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC 
   87360.0   262144.0   262144.0  87360.0   9792.0  87360.0  10048.0   262016.0   242048.0   317     4
NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC 
   1536.0   174592.0    13312.0  57856.0    512.0  57856.0    512.0   173568.0    11776.0  5475     2
6.jstat -gcold pid
          old代對象的信息。
   PC       PU        OC          OU       YGC    FGC    FGCT     GCT   
186368.0 114451.6    323200.0    211509.3    317     4    0.971    5.821
   MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT   
 39344.0  38142.6   4528.0   4303.1    260608.0    149783.6   5475     2    0.128   24.148
7.jstat -gcoldcapacity pid
          old代對象的信息及其佔用量。
   OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT   
   174784.0    786432.0    323200.0    323200.0   317     4    0.971    5.821
   OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT   
   260608.0    349696.0    260608.0    260608.0  5475     2    0.128   24.148
   
   
8.jstat -gcpermcapacity pid
          perm對象的信息及其佔用量。
  PGCMN      PGCMX       PGC         PC      YGC   FGC    FGCT     GCT   
  131072.0   262144.0   186368.0   186368.0   317     4    0.971    5.821
沒有
9.jstat -class pid
          顯示加載class的數量,及所佔空間等信息。
Loaded  Bytes  Unloaded  Bytes     Time   
 25315 45671.7     5976  7754.1      15.19
Loaded  Bytes  Unloaded  Bytes     Time   
  6472 11893.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
    4219   2232    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抓到的這些參數了。

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腳本的定時任務,我這裏定義的以下:

* */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]

    641036288

我這裏能夠獲取到數據了(注意IP被我註釋掉了,爲了保護隱私哈,包名也被我刻意修改了,隱私隱私哈)

接下來就能夠部署模板了,至於模板我已經作好了,能夠直接在附件裏面下載。至於模板我製做了一些簡單的key的值收集,以及圖像的展現,至於監控報警值的設置,因爲各個公司的環境不同,須要各位本身根據本身需求自行設置。


後記:

終於,寫完了,寫了一早上的博客,心好累,一早上沒怎麼作事,會不會被老大打死?

相關文章
相關標籤/搜索