概述
zabbix采用Trapper方式监控redis status
原理
redis-cli info命令得到redis服务器的统计信息,脚本对信息分两部分处理:
(1)# Keyspace部分为Zabbix agent,因为不确定db的数目所以此段的items也不确定,Zabbix server需要low level discovery(redis.discovery脚本)来确定db的数目以确定对redis服务器发起哪些items请求
(2)其余部分为Zabbix trapper,脚本整理这些信息并向Zabbix server发送(items要事先定义好)
配置
(1)Zabbix agent
low level discovery
item prototypes
userparameter_redis.conf
#Redis UserParameter=redis.discovery,/m2odata/server/zabbix-agent/scripts/lld-redis.py -a password UserParameter=redis[*],/m2odata/server/zabbix-agent/scripts/redis_zabbix.py $1 $2 $3 -a password
lld-redis.py
#!/usr/bin/env python #-*- coding: utf-8 -*- __author__ = 'pdd' __date__ = '2016/11/28' ''' redis db low level discovery ''' import re import json import redis def discovery(host, port, password): client = redis.StrictRedis(host=host, port=port, password=password) server_info = client.info() dbs = [('db%d' % x) for x in range(0,16) if ('db%d' % x) in server_info] # redis默认15个db data = [{"{#DBNAME}": db} for db in dbs] print(json.dumps({"data": data}, indent=4)) if __name__=='__main__': host = '127.0.0.1' port = 6379 password = 'password' discovery(host, port, password)
(2)Zabbix trapper # 一分钟发送一次数据到Zabbix server
*/1 * * * * /storage/server/zabbix-agent/scripts/redis_zabbix.py -a password
redis_zabbix.py
#!/usr/bin/python import redis, json, re, struct, time, socket, argparse parser = argparse.ArgumentParser(description='Zabbix Redis status script') parser.add_argument('redis_hostname',nargs='?') parser.add_argument('metric',nargs='?') parser.add_argument('db',default='none',nargs='?') parser.add_argument('-p','--port',dest='redis_port',action='store',help='Redis server port',default=6379,type=int) parser.add_argument('-a','--auth',dest='redis_pass',action='store',help='Redis server pass',default=None) args = parser.parse_args() zabbix_host = '127.0.0.1' #IP address of Zabbix Server # Zabbix Server IP zabbix_port = 10051 # Zabbix Server Port # Name of monitored server like it shows in zabbix web ui display redis_hostname = args.redis_hostname if args.redis_hostname else socket.gethostname() class Metric(object): def __init__(self, host, key, value, clock=None): self.host = host self.key = key self.value = value self.clock = clock def __repr__(self): result = None if self.clock is None: result = 'Metric(%r, %r, %r)' % (self.host, self.key, self.value) else: result = 'Metric(%r, %r, %r, %r)' % (self.host, self.key, self.value, self.clock) return result def send_to_zabbix(metrics, zabbix_host, zabbix_port): result = None j = json.dumps metrics_data = [] for m in metrics: clock = m.clock or ('%d' % time.time()) metrics_data.append(('{"host":%s,"key":%s,"value":%s,"clock":%s}') % (j(m.host), j(m.key), j(m.value), j(clock))) json_data = ('{"request":"sender data","data":[%s]}') % (','.join(metrics_data)) data_len = struct.pack('<Q', len(json_data)) packet = 'ZBXD\x01'+ data_len + json_data # For debug: #print(packet) #print(':'.join(x.encode('hex') for x in packet)) try: zabbix = socket.socket() zabbix.connect((zabbix_host, zabbix_port)) zabbix.sendall(packet) resp_hdr = _recv_all(zabbix, 13) if not resp_hdr.startswith('ZBXD\x01') or len(resp_hdr) != 13: print('Wrong zabbix response') result = False else: resp_body_len = struct.unpack('<Q', resp_hdr[5:])[0] resp_body = zabbix.recv(resp_body_len) zabbix.close() resp = json.loads(resp_body) # For debug # print(resp) if resp.get('response') == 'success': result = True else: print('Got error from Zabbix: %s' % resp) result = False except: print('Error while sending data to Zabbix') result = False finally: return result def _recv_all(sock, count): buf = '' while len(buf)<count: chunk = sock.recv(count-len(buf)) if not chunk: return buf buf += chunk return buf def main(): if redis_hostname and args.metric: client = redis.StrictRedis(host=redis_hostname, port=args.redis_port, password=args.redis_pass) server_info = client.info() if args.metric: if args.db and args.db in server_info.keys(): server_info['key_space_db_keys'] = server_info[args.db]['keys'] server_info['key_space_db_expires'] = server_info[args.db]['expires'] server_info['key_space_db_avg_ttl'] = server_info[args.db]['avg_ttl'] def list_key_space_db(): if args.db in server_info: print(args.db) else: print('database_detect') def default(): if args.metric in server_info.keys(): print(server_info[args.metric]) { 'list_key_space_db': list_key_space_db, }.get(args.metric, default)() else: print('Not selected metric'); else: client = redis.StrictRedis(host=redis_hostname, port=args.redis_port, password=args.redis_pass) server_info = client.info() a = [] for i in server_info: a.append(Metric(redis_hostname, ('redis[%s]' % i), server_info[i])) # Send packet to zabbix send_to_zabbix(a, zabbix_host, zabbix_port) if __name__ == '__main__': main()
参考:https://github.com/blacked/zbx_redis_template