通过修改Zabbix官方redis模板监控微软云Azure上多台MySQL实例

qingzhuoran 2017-10-10

由于微软云上的MySQL实例无法安装插件来导出数据,因此参考上一篇 通过Zabbix官方模板监控微软云Azure上多台Redis实例, 我们可以修改zabbix官方redis脚本,通过show status等命令获取到mysql的状态指标,用trap-messages模式发送给zabbix来监控微软云上的MySQL实例。

1. 运行环境:

OS:CentOS 7.3 / Python: 2.7.3/ Pip: 9.0.1  / Zabbix:3.2.8 / MySQL:微软云MySQL 5.7

Zabbix官方提供的redis监控模板,我们修改官方提供的python脚本来监控MySQL。

项目地址:https://github.com/blacked/zbx_redis_template

Zabbix所有官方模板:http://www.zabbix.org/wiki/Zabbix_Templates

2. 部署 

trap-messages方式的说明请参考上一篇 通过Zabbix官方模板监控微软云Azure上多台Redis实例。

1> 安装Python依赖

# yum -y install python-pip
# pip install argparse
# pip install pymysql

2> 将zbx_redis_stats.py放到zabbix服务器上某路径下并重命名,如/etc/zabbix/script/mysql/zbx_mysql_stats.py。

3> 修改脚本,下面是我修改的脚本,监控了show status获取的信息以及数据库表占用的空间等信息,可以直接拷贝,或者添加自己需要监控的其他信息。

# !/usr/bin/python

import sys, pymysql, json, re, struct, time, socket, argparse

parser = argparse.ArgumentParser(description='Zabbix MySQL status script')
parser.add_argument('mysql_hostname', nargs='?')
parser.add_argument('metric', nargs='?')
parser.add_argument('db', default='none', nargs='?')
parser.add_argument('-p', '--port', dest='mysql_port', action='store', help='MySQL server port', default=3306, type=int)
parser.add_argument('-a', '--auth', dest='mysql_pass', action='store', help='MySQL server pass', default=None)
parser.add_argument('-u', '--user', dest='mysql_user', action='store', help='MySQL server user', default=None)
args = parser.parse_args()

zabbix_host = '127.0.0.1'  # Zabbix Server IP
zabbix_port = 10051  # Zabbix Server Port

# Name of monitored server like it shows in zabbix web ui display
mysql_hostname = args.mysql_hostname if args.mysql_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 value_format(value):
    if value.isdigit() is True:
        value = int(value)
    return value


def send_to_zabbix(metrics, zabbix_host='127.0.0.1', zabbix_port=10051):
    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 mysql_hostname and args.metric:

        client = pymysql.connect(host=mysql_hostname, user=args.mysql_user, password=args.mysql_pass)
        cursor = client.cursor()
        cursor.execute("show status")
        data = cursor.fetchall()
        dict_local = {}
        for k, v in data:
            dict_local[k] = v

        cursor.execute("select SCHEMA_NAME from information_schema.schemata ")
        db = cursor.fetchall()
        dblist = []
        for i in db:
            dblist.append(i[0])

        if args.metric:
            def list_db():
                if args.db in dblist:
                    print(dblist)
                else:
                    print('database_detect')

            def default():
                if args.metric in dict_local.keys():
                    print(dict_local[args.metric])

            {
                'list_db': list_db
            }.get(args.metric, default)()

        else:
            print('Not selected metric')
    else:
        client = pymysql.connect(host=mysql_hostname, user=args.mysql_user, password=args.mysql_pass)
        cursor = client.cursor()
        cursor.execute("show status")
        data = cursor.fetchall()

        a = []
        for k, v in data:
            k = k.lower()
            v = value_format(v)
            a.append(Metric(mysql_hostname, ('azuremysql[%s]' % k), v))

        # cursor.execute("show processlist;")
        cursor.execute("select count(*) from information_schema.processlist;")
        processdata = cursor.fetchall()
        # process_count = len(processdata)
        process_count = processdata[0][0]
        a.append(Metric(mysql_hostname, 'azuremysql[process_count]', process_count))

        cursor.execute(
            "select table_schema,round(sum(data_length+index_length)/1024/1024,4) from information_schema.tables group by table_schema;")
        spacedata = cursor.fetchall()
        totalspace = 0
        for k, v in spacedata:
            a.append(Metric(mysql_hostname, ('azuremysql[%s]' % k), float(v)))
            totalspace += float(v)
        a.append(Metric(mysql_hostname, 'azuremysql[totalspace]', totalspace))

        # Send packet to zabbix
        send_to_zabbix(a, zabbix_host, zabbix_port)
        # for i in a:
        #  print(i)
        cursor.close()
        client.close()


if __name__ == '__main__':
    main()

通过修改Zabbix官方redis模板监控微软云Azure上多台MySQL实例
 
zbx_mysql_stats.py可以到安科网资源站下载:

------------------------------------------分割线------------------------------------------

具体下载目录在 /2017年资料/10月/10日/通过修改Zabbix官方redis模板监控微软云Azure上多台MySQL实例/

------------------------------------------分割线------------------------------------------

4>  测试脚本是否可以正常连接到微软云上MySQL并获取参数:

/etc/zabbix/script/mysql/zbx_mysql_status.py -u mysqluser -a mysqlpasswd test.mysqldb.chinacloudapi.cn list_db 

5> 添加crontab,定期执行脚本发送数据给zabbix,注意若密码中含有%需要用 \ 进行转义 (\%)。

  若要监控多台MySQL,则添加多个crontab:

*/1 * * * * /etc/zabbix/script/mysql/zbx_mysql_status.py -u mysqluser -a mysqlpasswd test.mysqldb.chinacloudapi.cn

6> 创建MySQL监控模板,注意监控项类型应选择"zabbix采集器",若使用的脚本,键值为"azuremysql[xxxxxxx]",否则请使用自己脚本定义的键值。

  附件是我创建的一个模板,添加了一些监控项,并不完整,可以在此基础上再添加需要的监控项。

  zbx_Azure_MySQL_template.xml  (下载见上面的安科网资源站)

7> 使用MySQL hostname创建主机,链接模板,即可实现zabbix监控。

通过修改Zabbix官方redis模板监控微软云Azure上多台MySQL实例

更多Zabbix相关教程集合: 

ZABBIX 的详细介绍:请点这里
ZABBIX 的下载地址:请点这里

相关推荐