zoukankan      html  css  js  c++  java
  • 利用Anemometer做mysql慢日志的查询与可视化

    Anemometer 是一个图形化显示MySQL慢日志的工具。结合pt-query-digest,Anemometer可以很轻松的帮你去分析慢查询日志,让你很容易就能找到哪些SQL需要优化。

    一、首先安装LNMP环境

    二、percona-toolkit工具的安装

    pt-query-digest是percona-toolkit里面一个工具,其作用就是分析慢查询日志,将MySQL慢查询日志进行统计并友好的显示出来

    1、安装依赖包

    [root@zabbix_server bin]# yum install perl-DBI perl-DBD-MySQL perl-IO-Socket-SSL perl-Digest-MD5 -y

    2、下载percona-toolkit二进制包

    [root@zabbix_server conf.d]# mkdir /usr/local/src/percona-toolkit
    [root@zabbix_server conf.d]# cd /usr/local/src/percona-toolkit
    [root@zabbix_server percona-toolkit]# wget https://www.percona.com/downloads/percona-toolkit/3.0.10/binary/tarball/percona-toolkit-3.0.10_x86_64.tar.gz
    --2020-04-07 16:44:49--  https://www.percona.com/downloads/percona-toolkit/3.0.10/binary/tarball/percona-toolkit-3.0.10_x86_64.tar.gz
    正在解析主机 www.percona.com... 74.121.199.234
    正在连接 www.percona.com|74.121.199.234|:443... 已连接。
    已发出 HTTP 请求,正在等待回应... 200 OK
    长度:8170395 (7.8M) [application/x-gzip]
    正在保存至: “percona-toolkit-3.0.10_x86_64.tar.gz”
    
    28% [============================>                                                                             ] 2,312,153    693K/s eta(英国中部时33% [==================================>                                                                       ] 2,770,905    759K/s eta(英国中部时39% [========================================>                                                                 ] 3,229,657    817K/s eta(英国中部时45% [==============================================>                                                           ] 3,688,409    871K/s eta(英国中部时50% [====================================================>                                                     ] 4,147,161    916K/s eta(英国中部时56% [==========================================================>                                               ] 4,605,913    953K/s eta(英国中部时61% [================================================================>                                         ] 5,064,665    986K/s eta(英国中部时67% [======================================================================>                                   ] 5,523,417   1014K/s eta(英国中部时73% [============================================================================>                             ] 5,982,169   1.02M/s eta(英国中部时77% [=================================================================================>                        ] 6,326,233   1.01M/s eta(英国中部时83% [=======================================================================================>                  ] 6,850,521   1.10M/s eta(英国中部时87% [============================================================================================>             ] 7,178,201   1.15M/s eta(英国中部时91% [================================================================================================>         ] 7,505,881   1.25M/s eta(英国中部时96% [=====================================================================================================>    ] 7,866,329   1.29M/s eta(英国中部时100%[=========================================================================================================>] 8,170,395   1.37M/s   in 7.1s    
    
    2020-04-07 16:44:59 (1.09 MB/s) - 已保存 “percona-toolkit-3.0.10_x86_64.tar.gz” [8170395/8170395])
    
    [root@zabbix_server percona-toolkit]# 

    解压

    [root@zabbix_server percona-toolkit]# tar -zxvf percona-toolkit-3.0.10_x86_64.tar.gz 
    percona-toolkit-3.0.10/
    percona-toolkit-3.0.10/CONTRIBUTE.md
    percona-toolkit-3.0.10/Makefile.PL
    percona-toolkit-3.0.10/docker-compose.yml
    percona-toolkit-3.0.10/CONTRIBUTING.md
    percona-toolkit-3.0.10/Gopkg.lock
    percona-toolkit-3.0.10/README.md
    percona-toolkit-3.0.10/bin/
    percona-toolkit-3.0.10/bin/pt-summary
    percona-toolkit-3.0.10/bin/pt-slave-delay
    percona-toolkit-3.0.10/bin/pt-mongodb-query-digest
    percona-toolkit-3.0.10/bin/pt-slave-restart
    percona-toolkit-3.0.10/bin/pt-variable-advisor
    percona-toolkit-3.0.10/bin/pt-fingerprint
    percona-toolkit-3.0.10/bin/pt-secure-collect
    percona-toolkit-3.0.10/bin/pt-index-usage
    percona-toolkit-3.0.10/bin/pt-archiver
    percona-toolkit-3.0.10/bin/pt-find
    percona-toolkit-3.0.10/bin/pt-heartbeat
    percona-toolkit-3.0.10/bin/pt-fifo-split
    percona-toolkit-3.0.10/bin/pt-fk-error-logger
    percona-toolkit-3.0.10/bin/pt-mysql-summary
    percona-toolkit-3.0.10/bin/pt-online-schema-change
    percona-toolkit-3.0.10/bin/pt-table-usage
    percona-toolkit-3.0.10/bin/pt-align
    percona-toolkit-3.0.10/bin/pt-query-digest
    percona-toolkit-3.0.10/bin/pt-ioprofile
    percona-toolkit-3.0.10/bin/pt-visual-explain
    percona-toolkit-3.0.10/bin/pt-stalk
    percona-toolkit-3.0.10/bin/pt-mext
    percona-toolkit-3.0.10/bin/pt-table-checksum
    percona-toolkit-3.0.10/bin/pt-show-grants
    percona-toolkit-3.0.10/bin/pt-pmp
    percona-toolkit-3.0.10/bin/pt-upgrade
    percona-toolkit-3.0.10/bin/pt-diskstats
    percona-toolkit-3.0.10/bin/pt-sift
    percona-toolkit-3.0.10/bin/pt-config-diff
    percona-toolkit-3.0.10/bin/pt-slave-find
    percona-toolkit-3.0.10/bin/pt-kill
    percona-toolkit-3.0.10/bin/pt-duplicate-key-checker
    percona-toolkit-3.0.10/bin/pt-deadlock-logger
    percona-toolkit-3.0.10/bin/pt-mongodb-summary
    percona-toolkit-3.0.10/bin/pt-table-sync
    percona-toolkit-3.0.10/lib/
    percona-toolkit-3.0.10/docs/
    percona-toolkit-3.0.10/docs/percona-toolkit.pod
    percona-toolkit-3.0.10/Gopkg.toml
    percona-toolkit-3.0.10/MANIFEST
    percona-toolkit-3.0.10/COPYING
    percona-toolkit-3.0.10/Changelog
    percona-toolkit-3.0.10/INSTALL
    [root@zabbix_server percona-toolkit]# mv percona-toolkit-3.0.10 /usr/local/

     3、运行查看版本

    [root@zabbix_server bin]# ./pt-query-digest --version
    pt-query-digest 3.0.10
    [root@zabbix_server bin]# 

    三、安装anemometer

    1、下载源码

    [root@zabbix_server www]# cd /var/www/
    [root@zabbix_server www]# git clone git://github.com/box/Anemometer.git anemometer
    Initialized empty Git repository in /var/www/anemometer/.git/
    remote: Enumerating objects: 1218, done.
    remote: Total 1218 (delta 0), reused 0 (delta 0), pack-reused 1218
    Receiving objects: 100% (1218/1218), 1.51 MiB | 2 KiB/s, done.
    Resolving deltas: 100% (627/627), done.
    [root@zabbix_server www]# 

    2、在nginx配置anemometer根目录

    server {
      2     listen       8083;
      3     server_name  172.28.18.75;
      4 
      5     #charset koi8-r;
      6     #access_log  /var/log/nginx/host.access.log  main;
      7 
      8     location / {
      9       root   /var/www/anemometer;
     10       index  index.php index.html index.htm;
     11     }
     12 

    浏览器打开http://172.28.18.75:8083

    3、配置目标数据库源

    首先复制一份示例配置文件sample.config.inc.php并改名为config.inc.php

    [root@zabbix_server conf]# cp sample.config.inc.php config.inc.php 
    [root@zabbix_server conf]# 

    首先修改数据库连接配置文件datasource_localhost.inc.php

    [root@zabbix_server conf]# vim datasource_localhost.inc.php 
    
      1 <?php
      2 $conf['datasources']['localhost'] = array(
      3     'host'  => 'localhost',
      4     'port'  => 3306,
      5     'db'    => 'slow_query_log',
      6     'user'  => 'root',
      7     'password' => 'xxxxxxxx',
      8     'tables' => array(
      9         'global_query_review' => 'fact',
     10         'global_query_review_history' => 'dimension'
     11     ),
     12     'source_type' => 'slow_query_log'
     13 );
     14 

    db:slow_query_log :这是慢查询日志存放的数据库,由/var/www/anemometer/install.sql脚本创建,下面的操作将会有导入这个SQL文件

    4、导入install.sql初始化数据源的数据库表的配置

    mysql> source /var/www/anemometer/install.sql;
    Query OK, 0 rows affected, 1 warning (0.05 sec)
    
    Query OK, 1 row affected (0.00 sec)
    
    Database changed
    Query OK, 0 rows affected (0.10 sec)
    
    ERROR 1067 (42000): Invalid default value for 'ts_min'

    报错,查看install.sql,发现ts_min列的定义为`ts_min` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',

    这是mysql5.7以上版本里设置的sql_mode参数的关系,查看sql_mode参数设置

    mysql> show variables like '%sql_mode%';
    +---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
    | Variable_name | Value                                                                                                                                     |
    +---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
    | sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
    +---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
    1 row in set (0.01 sec)
    NO_ZERO_IN_DATE,NO_ZERO_DATE:表示不允许日期数据为零值,将sql_mode重新设置
    mysql> set sql_mode='STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    mysql> show variables like '%sql_mode%';
    +---------------+-------------------------------------------------------------------------------------------+
    | Variable_name | Value                                                                                     |
    +---------------+-------------------------------------------------------------------------------------------+
    | sql_mode      | STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
    +---------------+-------------------------------------------------------------------------------------------+
    1 row in set (0.00 sec)

    再导入install.sql

    mysql> source /var/www/anemometer/install.sql;
    Query OK, 1 row affected (0.00 sec)
    
    Query OK, 1 row affected (0.00 sec)
    
    Database changed
    Query OK, 0 rows affected (0.01 sec)
    
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> 

    新建了一个slow_query_log数据库里面新建了两个表:global_query_review和global_query_review_history,用于保存从目标数据库利用pt-query-digest工具收集的慢日志数据。

    5、在目标数据库上使用pt-query-digest工具收集日志推送到slow_query_log数据库中

    [root@zabbix_server bin]# ./pt-query-digest --user=root --password=Zaq1xsw@ --review h=172.28.18.75,D=slow_query_log,t=global_query_review --history h=172.28.18.75,D=slow_query_log,t=global_query_review_history --no-report --limit=0% --filter=" $event->{Bytes} = length($event->{arg}) and $event->{hostname}="$HOSTNAME"" /home/mysql_data/mysql/zabbix_server-slow.log 

    执行完上面语句,global_query_review和global_query_review_history就会有统计的数据信息

    刷新页面,可以看到慢日志数据展示

    四、数据库说明

    主要字段说明:

    •     hostname_max : MySQL服务所在主机名称
    •     db_max: 数据库名称
    •     checksum : 同global_query_review表中的checksum,两张表通过该值关联
    •     sample : sql示例
    •     ts_min : 本次统计(每10分钟一次)该类型sql语句出现的最小时间
    •     ts_max: 本次统计(每10分钟一次)该类型sql语句出现的最大时间
    •     ts_cnt : 本次统计该sql语句出现的次数
    •     Query_time_sum : 本次统计该类型sql语句花费的总时间
    •     Query_time_min : 本次统计该类型sql语句执行最快的那个sql语句花费的时间
    •     Query_time_max: 本次统计该类型sql语句执行最慢的那个sql语句花费的时间
    •     Query_time_pct_95: 本次统计该类型sql语句执行时间位于95%分位的sql执行时间
    •     Query_time_stddev: 本次统计该类型sql语句执行时间标准差(统计学概念)
    •     Query_time_median: 本次统计该类型sql语句执行时间位于中位数位置的sql执行时间
    •     index_ratio:表示的是扫描的行数/返回的结果行数

     五、配置anemometer

    1、首先将“custom_fields“数组里的”'snippet' => 'LEFT(dimension.sample,50)'改为'snippet' => 'dimension.sample',

    2、history表里的ts_cnt列是Sum出来的,如果我们5分钟收集一次日志,这个结果完全不是想要的,增加一个数组元素'query_cnt' => 'MAX(ts_cnt)',这个数据为语句的执行次数,并且将history_defaults和report_defaults的table_fields配置中将ts_cnt改为了query_cnt。

    3、单个查询的过去90天历史记录里,它是以ts_min为group by的,因为history表里ts_min只有一个值,既语句第一次执行的时间,所以这会只显示一条数据,而不是每天的数据,这里改成ts_max。既语句最后执行时间将'date'  => 'DATE(ts_min)改为'ate'  => 'DATE(ts_max)'

    4、$conf['report_defaults'] = array数组保存页面统计列表里的数据字段和查询条件,可以在这里进行个性化设置,来显示需要的数据

    // custom fields
    339     'custom_fields' => array(
    340         'checksum' => 'checksum',
    341         'snippet' => 'dimension.sample',
    342         'query_cnt' => 'MAX(ts_cnt)',
    343         'query_max' => 'ROUND(MAX(query_time_max),2)',
    344         'query_min' => 'ROUND(MIN(Query_time_min),2)',
    345         'query_avg' => 'ROUND(SUM(Query_time_sum)/SUM(ts_cnt),2)',
    346         'lock_max' => 'ROUND(MAX(Lock_time_max),4)',
    347         'lock_min' => 'ROUND(MIN(Lock_time_min),4)',
    348         'lock_avg' => 'ROUND(SUM(Lock_time_sum)/SUM(ts_cnt),4)',
    349         'rows_sent_avg' => 'ROUND(SUM(Rows_sent_sum)/SUM(ts_cnt))',
    350         'rows_examined_avg' => 'ROUND(SUM(Rows_examined_sum)/SUM(ts_cnt))',
    351         'date'  => 'DATE(ts_max)',
    352         'hour'  => 'substring(ts_min,1,13)',
    353         'hour_ts'   => 'round(unix_timestamp(substring(ts_min,1,13)))',
    354         'minute_ts'     => 'round(unix_timestamp(substring(ts_min,1,16)))',
    355         'minute'        => 'substring(ts_min,1,16)',

    5、对于某些慢日志里Query ID 是0xFF6BA40AE1ADBA294B52E89F1929E3F8类似这样的ID,在页面显示中会查询不到历史记录,这是因为Anemometer把checksum列设置为了bigint类型,所以,我们需要将checksum列设置为varchar(60)字符型,并修改PHP代码中相应的地方

    修改config.inc.php文件,搜索"dec2hex"

    将这句注释掉

    360     'callbacks'     => array(
    361         'table' => array(
    362             'date'  => function ($x) { $type=''; if ( date('N',strtotime($x)) >= 6) { $type = 'weekend'; } return array($x,$type); },
    363             #'checksum' => function ($x) { return array(dec2hex($x), ''); }
    364         )
    365     )

    修改lib/Anemometer.php文件搜索"translate_checksum()"函数,将里面的"return $this->bchexdec($checksum);"注释掉,在下面增加一句"return $checksum;"

    private function translate_checksum($checksum)
    359     {
    360     if (!in_array($this->data_model->get_source_type(), array('slow_query_log','default')))
    361     {
    362         return $checksum;
    363     }
    364 
    365         if (preg_match('/^[0-9]+$/', $checksum))
    366         {
    367             return $checksum;
    368         }
    369         else if (preg_match('/^[0-9A-Fa-f]+$/', $checksum))
    370         {
    371             #return $this->bchexdec($checksum);
    372             return $checksum;
    373         }
    374         else if (strlen($checksum) == 0)
    375         {
    376             return null;
    377         }
    378         else
    379         {
    380             throw new Exception("Invalid query checksum");
    381         }
    382     }

    修改AnemometerModel.php 文件里相关使用$checksum作为条件查询的语句,在变量的两边加上单引号,表示引用的是字符串

    搜索"$checksum"进行相应修改

    public function checksum_exists($checksum) {
    200         $checksum_field_name = $this->get_field_name('checksum');
    201         $query = "SELECT `{$checksum_field_name}` FROM `{$this->fact_table}` WHERE `{$checksum_field_name}`='" . $this->mysqli->real_escape_string($checksum) . "'";
    public function update_query($checksum, $fields) {
    218         $mysqli = $this->mysqli;
    219         $checksum_field_name = $this->get_field_name('checksum');
    220         $sql = "UPDATE `{$this->fact_table}` SET ";
    221         $sql .= join(
    222                 ',', array_map(
    223                         function ($x, $y) use ($mysqli) {
    224                             if ($y == 'NULL') {
    225                                 return "{$x} = NULL";
    226                             }
    227                             return "`{$x}` = "" . $mysqli->real_escape_string($y) . '"';
    228                         }, array_keys($fields), array_values($fields)
    229                 )
    230         );
    231         $sql .= " WHERE `{$checksum_field_name}`='" . $this->mysqli->real_escape_string($checksum) . "'";
    public function get_query_by_checksum($checksum) {
    244         $checksum_field_name = $this->get_field_name('checksum');
    245         $result = $this->mysqli->query("SELECT * FROM `{$this->fact_table}` WHERE `{$checksum_field_name}`='{$checksum}'");
    246         check_mysql_error($result, $this->mysqli);
    247         if ($row = $result->fetch_assoc()) {
    248             return $row;
    249         }
    250         return null;
    251     }
    public function get_query_samples($checksum, $limit = 1, $offset = 0) {
    262         $checksum_field_name = $this->get_field_name('checksum');
    263         $time_field_name = $this->get_field_name('time');
    264         $table = $this->dimension_table;
    265         if ($this->get_source_type() == 'performance_schema')
    266         {
    267             $table = $this->fact_table;
    268         }
    269         $sql = "SELECT * FROM `{$table}` WHERE `{$checksum_field_name}`='{$checksum}' ORDER BY `{$time_field_name}` DESC LIMIT {$limit} OFFSET     {$offset}";
    270         return $this->mysqli->query($sql);
    271     }
    public function checksum_exists($checksum) {
    200         $checksum_field_name = $this->get_field_name('checksum');
    201         $query = "SELECT `{$checksum_field_name}` FROM `{$this->fact_table}` WHERE `{$checksum_field_name}`='" . $this->mysqli->real_escape_string($checksum) . "'";
    202         //print "query: {$query}<br>"; 
    203         $result = $this->mysqli->query($query);
    204         check_mysql_error($result, $this->mysqli);
    205         if ($result->num_rows) {
    206             return true;
    207         }
    208         return false;
    209     }

    保存退出后,即可查询正常

  • 相关阅读:
    第三周课程总结
    Java第一次学习总结
    第十二周编程总结
    第九周作业
    第八周作业
    第五周编程总结
    第三周作业
    第二周编程总结
    JAVA第二周学习总结
    2019春总结作业
  • 原文地址:https://www.cnblogs.com/sky-cheng/p/12654386.html
Copyright © 2011-2022 走看看