JAVA-GATEWAY

Zabbix本身不支持直接监控Java,在zabbix 1.8以前,只能使用Zapcat来做代理监控,

而且要修改源代码,非常麻烦。所有后来为了解决这个监控问题,

Zabbix和Java双方应运生成了各自的代理监控程序:zabbix 2.0以后添加了服务进程

zabbix-java-gateway;Java有了JMX,全称是Java Management Extensions,即Java管理扩展

wKioL1hA8FKiTpeWAABu7oWbNfE824.png

比如:当Zabbix-Server需要知道java应用程序的某项性能的时候,

会启动自身的一个Zabbix-JavaPollers进程去连接Zabbix-JavaGateway请求数据,

而ZabbixJavagateway收到请求后使用“JMXmanagementAPI”去查询特定的应用程序,

而前提是应用程序这端在开启时需要“-Dcom.sun.management.jmxremote”参数来

开启JMX远程查询就行。

Java程序会启动自身的一个简单的小程序端口12345向Zabbix-JavaGateway提供请求数据。


开始监控部署  

从上面的原理图中我们可以看出,配置Zabbix监控Java应用程序的关键点在于:

配置Zabbix-JavaGateway、让Zabbix-Server能够连接Zabbix-JavaGateway、

Tomcat开启JVM远程监控功能等





网上的大多数文章都配置的是被动模式(即zabbix server 去想java进程去取数据),

这样会造成zabbix server的压力过大,所以应该采用主动模式(写一个zabbix类,然后主动去上报数据)


代码如下:

zabbix.py

1
<span style = "font-family:sans-serif;" ><span style = "font-size:16px;" >cat zabbix.py<br data - filtered = "filtered" > #!/usr/bin/python<br data-filtered="filtered">import os<br data-filtered="filtered">import time<br data-filtered="filtered">import socket<br data-filtered="filtered">import struct<br data-filtered="filtered">import cPickle<br data-filtered="filtered">import logging<br data-filtered="filtered">try:<br data-filtered="filtered">    from hashlib import sha1<br data-filtered="filtered">except ImportError:<br data-filtered="filtered">    from sha import sha as sha1<br data-filtered="filtered">try:<br data-filtered="filtered">    import json<br data-filtered="filtered">except ImportError:<br data-filtered="filtered">    import simplejson as json<br data-filtered="filtered">DUMP = 'dump'<br data-filtered="filtered">if not os.path.isdir(DUMP):<br data-filtered="filtered">    os.makedirs(DUMP, mode=0755)<br data-filtered="filtered">class Zabbix(object):<br data-filtered="filtered">    logger = logging.getLogger('zabbix')<br data-filtered="filtered">    def __init__(self, values=None):<br data-filtered="filtered">        if values is not None:<br data-filtered="filtered">            self.__dict__['values'] = values<br data-filtered="filtered">    def __getattr__(self, name):<br data-filtered="filtered">        if name in ('values'):<br data-filtered="filtered">            return self.__dict__[name]<br data-filtered="filtered">        return None<br data-filtered="filtered">    def __setattr__(self, name, value):<br data-filtered="filtered">        if name == 'values':<br data-filtered="filtered">            self.__dict__[name] = value<br data-filtered="filtered">    def gen_request(self, jsons):<br data-filtered="filtered">        if isinstance(jsons, basestring):<br data-filtered="filtered">            data = '%s\n' % jsons<br data-filtered="filtered">        else:<br data-filtered="filtered">            data = json.dumps(jsons)<br data-filtered="filtered">        header = 'ZBXD\x01'<br data-filtered="filtered">        datalen = struct.pack('Q', len(data))<br data-filtered="filtered">        return header + datalen + data<br data-filtered="filtered">    def dump(self, host, port, jsons):<br data-filtered="filtered">        data = {'host': host, 'port': port, 'jsons': jsons}<br data-filtered="filtered">        hash = sha1(json.dumps(data)).hexdigest()<br data-filtered="filtered">        path = '%s.%s.%d.%s.error' % (host, port, int(time.time()), hash)<br data-filtered="filtered">        try:<br data-filtered="filtered">            write = open(os.path.join(DUMP, path), 'wb')<br data-filtered="filtered">            cPickle.dump(data, write, -1)<br data-filtered="filtered">            write.close()<br data-filtered="filtered">        except:<br data-filtered="filtered">            self.logger.exception('cannot dump to file %s', path)<br data-filtered="filtered">    def get_zbx_result(self, host, port, jsons):<br data-filtered="filtered">        retry = 3<br data-filtered="filtered">        while retry:<br data-filtered="filtered">            try:<br data-filtered="filtered">                data = self._get_zbx_result(host, port, jsons)<br data-filtered="filtered">                if data is None:<br data-filtered="filtered">                    break<br data-filtered="filtered">                return data<br data-filtered="filtered">            except socket.error:<br data-filtered="filtered">                self.logger.exception('cannot communit with zabbix')<br data-filtered="filtered">            time.sleep(5)<br data-filtered="filtered">            retry -= 1<br data-filtered="filtered">        self.logger.error('cannot send data to zabbix server')<br data-filtered="filtered">        self.dump(host, port, jsons)<br data-filtered="filtered">    def _get_zbx_result(self, host, port, jsons):<br data-filtered="filtered">        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br data-filtered="filtered">        print host,port,jsons<br data-filtered="filtered">        sock.connect((host, port))<br data-filtered="filtered">        sock.send(self.gen_request(jsons))<br data-filtered="filtered">        print "send %s" % self.gen_request(jsons)<br data-filtered="filtered">        self.logger.debug('sent %s', jsons)<br data-filtered="filtered">        recv = sock.recv(5)<br data-filtered="filtered">        if recv != 'ZBXD\x01':<br data-filtered="filtered">            self.logger.error('Invalid Response')<br data-filtered="filtered">            self.dump(host, port, jsons)<br data-filtered="filtered">            return None<br data-filtered="filtered">        recv = sock.recv(8)<br data-filtered="filtered">        (datalen,) = struct.unpack('Q', recv)<br data-filtered="filtered">        data = sock.recv(datalen)<br data-filtered="filtered">        sock.close()<br data-filtered="filtered">        self.logger.debug('received %s', data)<br data-filtered="filtered">        return data<br data-filtered="filtered">    def getvalue(self):<br data-filtered="filtered">        # shoulde be {host: {key: value}}<br data-filtered="filtered">        return self.values<br data-filtered="filtered">    def run(self):<br data-filtered="filtered">        hostvalues = self.getvalue()<br data-filtered="filtered">        if not isinstance(hostvalues, dict):<br data-filtered="filtered">            self.logger.error('invalid hostvalues: %s', str(hostvalues))<br data-filtered="filtered">            return False<br data-filtered="filtered">        clock = int(time.time())<br data-filtered="filtered">        jsons = {<br data-filtered="filtered">            'request': 'agent data',<br data-filtered="filtered">            'data': [],<br data-filtered="filtered">            'clock': clock,<br data-filtered="filtered">        }<br data-filtered="filtered">        data = jsons['data']<br data-filtered="filtered">        for host, values in hostvalues.iteritems():<br data-filtered="filtered">            for key, value in values.iteritems():<br data-filtered="filtered">                data.append({<br data-filtered="filtered">                    'host': host,<br data-filtered="filtered">                    'key': key,<br data-filtered="filtered">                    'value': value,<br data-filtered="filtered">                    'clock': clock,<br data-filtered="filtered">                })<br data-filtered="filtered">        return self.get_zbx_result(ZBX_HOST, ZBX_PORT, jsons)<br data-filtered="filtered">    def getjmx(self, host, port, keys):<br data-filtered="filtered">        jsons = {<br data-filtered="filtered">            'request': 'java gateway jmx',<br data-filtered="filtered">            'conn': host,<br data-filtered="filtered">            'port': port,<br data-filtered="filtered">            'keys': keys,<br data-filtered="filtered">        }<br data-filtered="filtered">        return self.get_zbx_result(JMX_HOST, JMX_PORT, jsons)<br data-filtered="filtered">ZBX_HOST = 'zabbix.server.com'<br data-filtered="filtered">ZBX_PORT = 10051<br data-filtered="filtered">JMX_HOST = 'localhost'<br data-filtered="filtered">JMX_PORT = 10052<br data-filtered="filtered">handler = logging.FileHandler(filename='/tmp/zabbix.%s.log' % time.strftime('%Y%m%d'), mode='a')<br data-filtered="filtered">formatter = logging.Formatter('%(asctime)s %(name)s %(lineno)s %(levelname)s %(message)s')<br data-filtered="filtered">handler.setFormatter(formatter)<br data-filtered="filtered">logger = logging.getLogger()<br data-filtered="filtered">logger.addHandler(handler)<br data-filtered="filtered">logger.setLevel(logging.DEBUG)<br data-filtered="filtered">if __name__ == '__main__':<br data-filtered="filtered">    zbx = Zabbix()<br data-filtered="filtered">    print zbx.getjmx('localhost', 8081, ['jmx["Standalone:type=Manager,path=/,host=localhost",activeSessions]', 'jmx["java.lang:type=Runtime",Uptime]', 'jmx["Catalina:type=GlobalRequestProcessor,name=\\"http-bio-8080\\"",bytesSent]'])<br data-filtered="filtered">    pass<br data-filtered="filtered"></span></span>



cat zabbix_wiki_node1_java.py   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/env python
#fileencoding: utf-8
ITEMS  =  [
'jmx["java.lang:type=ClassLoading",LoadedClassCount]' ,
'jmx["java.lang:type=ClassLoading",TotalLoadedClassCount]' ,
'jmx["java.lang:type=ClassLoading",UnloadedClassCount]' ,
'jmx["java.lang:type=Memory",HeapMemoryUsage.committed]' ,
'jmx["java.lang:type=Memory",HeapMemoryUsage.max]' ,
'jmx["java.lang:type=Memory",HeapMemoryUsage.used]' ,
'jmx["java.lang:type=Memory",NonHeapMemoryUsage.committed]' ,
'jmx["java.lang:type=Memory",NonHeapMemoryUsage.max]' ,
'jmx["java.lang:type=Memory",NonHeapMemoryUsage.used]' ,
'jmx["java.lang:type=MemoryPool,name=Code Cache",Usage.committed]' ,
'jmx["java.lang:type=MemoryPool,name=Code Cache",Usage.max]' ,
'jmx["java.lang:type=MemoryPool,name=Code Cache",Usage.used]' ,
'jmx["java.lang:type=MemoryPool,name=PS Eden Space",Usage.committed]' ,
'jmx["java.lang:type=MemoryPool,name=PS Eden Space",Usage.max]' ,
'jmx["java.lang:type=MemoryPool,name=PS Eden Space",Usage.used]' ,
'jmx["java.lang:type=MemoryPool,name=PS Old Gen",Usage.committed]' ,
'jmx["java.lang:type=MemoryPool,name=PS Old Gen",Usage.max]' ,
'jmx["java.lang:type=MemoryPool,name=PS Old Gen",Usage.used]' ,
'jmx["java.lang:type=MemoryPool,name=PS Perm Gen",Usage.committed]' ,
'jmx["java.lang:type=MemoryPool,name=PS Perm Gen",Usage.max]' ,
'jmx["java.lang:type=MemoryPool,name=PS Perm Gen",Usage.used]' ,
'jmx["java.lang:type=MemoryPool,name=PS Survivor Space",Usage.committed]' ,
'jmx["java.lang:type=MemoryPool,name=PS Survivor Space",Usage.max]' ,
'jmx["java.lang:type=MemoryPool,name=PS Survivor Space",Usage.used]' ,
'jmx["java.lang:type=OperatingSystem",MaxFileDescriptorCount]' ,
'jmx["java.lang:type=OperatingSystem",OpenFileDescriptorCount]' ,
'jmx["java.lang:type=Runtime",Uptime]' ,
'jmx["java.lang:type=Threading",DaemonThreadCount]' ,
'jmx["java.lang:type=Threading",PeakThreadCount]' ,
'jmx["java.lang:type=Threading",ThreadCount]' ,
'jmx["java.lang:type=Threading",TotalStartedThreadCount]' ,
'jmx["Standalone:type=GlobalRequestProcessor,name=http-8090",bytesReceived]' ,
'jmx["Standalone:type=GlobalRequestProcessor,name=http-8090",bytesSent]' ,
'jmx["Standalone:type=GlobalRequestProcessor,name=http-8090",errorCount]' ,
'jmx["Standalone:type=GlobalRequestProcessor,name=http-8090",processingTime]' ,
'jmx["Standalone:type=GlobalRequestProcessor,name=http-8090",requestCount]' ,
'jmx["Standalone:type=Manager,path=/,host=localhost",activeSessions]' ,
'jmx["Standalone:type=Manager,path=/,host=localhost",maxActiveSessions]' ,
'jmx["Standalone:type=Manager,path=/,host=localhost",maxActive]' ,
'jmx["Standalone:type=Manager,path=/,host=localhost",rejectedSessions]' ,
'jmx["Standalone:type=Manager,path=/,host=localhost",sessionCounter]' ,
'jmx["Standalone:type=ProtocolHandler,port=8090",compression]' ,
'jmx["Standalone:type=ThreadPool,name=http-8090",currentThreadCount]' ,
'jmx["Standalone:type=ThreadPool,name=http-8090",currentThreadsBusy]' ,
'jmx["Standalone:type=ThreadPool,name=http-8090",maxThreads]' ,
]
from  zabbix  import  Zabbix
from  zabbix  import  json
def  getjmxkey(key):
     # key = key.replace('http-8080', '\\"http-bio-8080\\"')
     # key = key.replace('path=/', 'context=/')
     return  key
def  getjmxvalue(value):
     if  isinstance (value,  dict ):
         return  value.get( 'value' , u' ').encode(' utf8')
     return  ''
if  __name__  = =  '__main__' :
     host  =  'it-tw01'
     zbx  =  Zabbix()
     jmxkeys  =  [getjmxkey(x)  for  in  ITEMS]
     data  =  zbx.getjmx( 'it-tw01' '8410' , jmxkeys)
     try :
         results  =  json.loads(data)
     except :
         results  =  {}
     if  isinstance (results,  dict and  results[ 'response' = =  'success' :
         jmxvalues  =  [getjmxvalue(x)  for  in  results.get( 'data' , [])]
         hostvalues  =  {host:  dict ( zip (ITEMS, jmxvalues))}
         Zabbix(hostvalues).run()
# vim: set sta sw=4 et:


crontab

* * * * * /home/sankuai/monitor/zabbix_wiki_node1_java.py


zabbix

/etc/zabbix# ls

zabbix_agentd.conf  zabbix_agentd.confn-place  zabbix_agentd.d  zabbix_java_gateway.conf


it-tw01需要关联的模板见附件




特别注意:

编译安装zabbix server需要加上--enable-java以支持jmx监控,如果之前的zabbix server没加,那么请重新编译安装,参考编译参数

安装软件

yum install -y java java-devel zabbix-java-gateway

更多的请参考这个文章:http://www.iyunv.com/thread-269939-1-1.html