通过zabbix监控mysql的tps和qps,我们之前的percona mysql模板是没有关于这两个监控项的,需要我们通过脚本进行统计分析。
一、脚本思路:

#统计qps来源
show global status where Variable_name in('com_select','com_insert','com_delete','com_update');
#统计tps来源
show global status where Variable_name in('com_commit','com_rollback');

1.通过以上两条sql可以统计mysql从启动开始运行至今所有的qps、tps来源,我们每5分钟统计一次,使用(第二次-第一次)/时间差,可以得到qps、tps。
2.为了避免每次读库并提高脚本运行的效率,我们将本次的qps、tps来源存入临时文件,以便下次计算使用
3.由于脚本第一次运行没有临时文件或临时文件为空,因此我们通过延迟1秒读两次库,两次统计之差直接得到本次的qps
4.后续使用临时文件中的数据即可

二、脚本如下

#!/usr/bin/env python
#-*- coding: utf8 -*-
#date: 2018-04-12
#author: yanggd
#comment: 计算mysql的qps和tps

import MySQLdb
import time
import sys
import os

class Mysql(object):
        def __init__(self, host, port, user, passwd, db, unix_socket='/tmp/mysql.sock'):
                self.host = host
                self.port = port
                self.user = user
                self.passwd = passwd
                self.db = db
                self.unix_socket = unix_socket
                self.conn = MySQLdb.connect(host=self.host,port=self.port,user=self.user,passwd=self.passwd,db=self.db,unix_socket=self.unix_socket)
                self.cursor = self.conn.cursor()

        def queryQps(self):
                #获取qps来源
                sql = "show global status where Variable_name in('com_select','com_insert','com_delete','com_update');"
                self.cursor.execute(sql)
                return self.cursor.fetchall()

        def queryTps(self):
                #获取tps来源
                sql = "show global status where Variable_name in('com_commit','com_rollback');"
                self.cursor.execute(sql)
                return self.cursor.fetchall()

        def closeDB(self):
                self.cursor.close()
                self.conn.close()

class Qps(object):
        def __init__(self,qps_com):
                self.qps_com = qps_com
        def getQps(self):
                qps_total = 0
                for res in self.qps_com:
                        qps_total += int(res[1])
                return qps_total


class Tps(object):
        def __init__(self,tps_com):
                self.tps_com = tps_com
        def getTps(self):
                tps_total = 0
                for res in self.tps_com:
                        tps_total += int(res[1])
                return tps_total

if __name__ == '__main__':
        #时间间隔
        diff = 300
        #临时存放上次的qps,tps文件
        qps_before = '/tmp/qps'
        tps_before = '/tmp/tps'

        mysql = Mysql('localhost',3306,'root','test','')

        if len(sys.argv) <> 2:
                print "Usage: " + sys.argv[0] + ' qps|tps'
        elif sys.argv[1] == 'qps':
                #若临时文件不存在或数据为空,通过延迟1秒,来获取本次的qps;最后将本次的qps来源数据存放到临时文件,供下次使用
                if not os.path.exists(qps_before) or os.path.getsize(qps_before) == 0:
                        qps_com = mysql.queryQps()
                        qps = Qps(qps_com)
                        q1 = qps.getQps()

                        time.sleep(1)

                        qps_com = mysql.queryQps()
                        qps = Qps(qps_com)
                        q2 = qps.getQps()

                        print (q2-q1)

                        with open(qps_before, 'w') as f:
                                f.write(str(q2))

                #若临时文件存在且有数据,获取上次qps并计算;最后将本次的qps来源数据存放到临时文件,供下次使用
                else:
                        qps_com = mysql.queryQps()
                        qps = Qps(qps_com)
                        qps_cur = qps.getQps()

                        with open(qps_before) as f:
                                qps_last=f.read()

                        print (qps_cur-int(qps_last))/diff

                        with open(qps_before, 'w') as f:
                                f.write(str(qps_cur))

        elif sys.argv[1] == 'tps':
                #若临时文件不存在或数据为空,通过延迟1秒,来获取本次的tps;最后将本次的tps来源数据存放到临时文件,供下次使用
                if not os.path.exists(tps_before) or os.path.getsize(tps_before) == 0:
                        tps_com = mysql.queryTps()
                        tps = Tps(tps_com)
                        t1 = tps.getTps()

                        time.sleep(1)

                        tps_com = mysql.queryTps()
                        tps = Tps(tps_com)
                        t2 = tps.getTps()

                        print (t2-t1)

                        with open(tps_before, 'w') as f:
                                f.write(str(t2))

                #若临时文件存在且有数据,获取上次tps并计算;最后将本次的tps来源存放到临时文件,供下次使用
                else:
                        tps_com = mysql.queryTps()
                        tps = Tps(tps_com)
                        tps_cur = tps.getTps()
                        with open(tps_before) as f:
                                tps_last=f.read()

                        print (tps_cur-int(tps_last))/diff

                        with open(tps_before, 'w') as f:
                                f.write(str(tps_cur))

        else:
                print "请输入正确参数: qps|tps"

        mysql.closeDB()

三、配置zabbix agent

cd /etc/zabbix/zabbix_agentd.d/
vim userparameter_tps_qps.conf
UserParameter=mysql.qps,python /App/scripts/zabbix/mysql_qps_tps.py qps
UserParameter=mysql.tps,python /App/scripts/zabbix/mysql_qps_tps.py tps

四、配置percona mysql模板

1.配置监控项

QL Server Management Studio怎么监控性能 qps 监控_mysql tps qps


2.配置图形

QL Server Management Studio怎么监控性能 qps 监控_mysql_02

注意:时间间隔为300s,我们每5分钟统计一次。

mysql tps的监控项和图像也按如上配置。

四、总结
除了上述方式,还可以使用:
基于 questions 计算qps,基于 com_commit com_rollback 计算tps

questions = show global status like 'questions';
uptime = show global status like 'uptime';
qps=questions/uptime

com_commit = show global status like 'com_commit';
com_rollback = show global status like 'com_rollback';
uptime = show global status like 'uptime';
tps=(com_commit + com_rollback)/uptime

Questions 是记录了从mysqld启动以来所有的select,dml 次数包括show 命令的查询的次数。这样多少有失准确性,比如很多数据库有监控系统在运行,每5秒对数据库进行一次show 查询来获取当前数据库的状态,而这些查询就被记录到QPS,TPS统计中,造成一定的”数据污染”。