前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pt-kill 输出信息优化

pt-kill 输出信息优化

作者头像
保持热爱奔赴山海
发布2022-11-14 16:47:04
4580
发布2022-11-14 16:47:04
举报
文章被收录于专栏:数据库相关数据库相关

默认情况下,pt-kill (3.3.1版本) 的执行记录如果是输出到log文件的话,日志里面是不会带上 库名、客户端地址的,类似如下:

pt-kill 输出信息优化_pt-kill
pt-kill 输出信息优化_pt-kill

我们可以简单修改下代码, 让其支持该属性的输出。

代码语言:javascript
复制
$ cd /usr/bin/

$ pt-kill --version
pt-kill 3.3.1

$ cp pt-kill pt-kill_20221028_bak

修改前:
         foreach my $query ( @queries ) {
            if ( $o->get('print') ) {
               printf "# %s %s %d (%s %d sec) %s\n",
                  ts(time), $o->get('kill-query') ? 'KILL QUERY' : 'KILL',
                  $query->{Id}, ($query->{Command} || 'NULL'), $query->{Time},
                  ($query->{Info} || 'NULL');
            }    
            if ( $o->get('query-id') ) {
                  my $fp = $qr->fingerprint($query->{'Info'});
                  my $chksm = Transformers::make_checksum($fp);
                  print "Query ID: 0x$chksm\n";
            } 



修改后:
            if ( $o->get('print') ) {
                printf "# 检测时间: %s ,操作类型: %s ,Query_Id: %d ,用户名: %s ,客户端地址: %s ,库名: %s (%s %d sec) ,SQL明细: %s\n",
                    ts(time), ($o->get('kill-query') ||$o->get('kill')) ? 'KILL QUERY OR KILL' : 'ONLY_PRINT',
                    $query->{Id},$query->{User},$query->{Host},($query->{db} ? $query->{db} :'none'),($query->{Command} || 'NULL'), $query->{Time},
                   ($query->{Info} || 'NULL');
             }    
            if ( $o->get('query-id') ) {
                  my $fp = $qr->fingerprint($query->{'Info'});
                  my $chksm = Transformers::make_checksum($fp);
                  print "Query ID: 0x$chksm\n";
            }
pt-kill 输出信息优化_pt-kill_02
pt-kill 输出信息优化_pt-kill_02

修改完成后,我们执行下pt-kill命令,如下(演示的过滤条件很暴力):

pt-kill u=dts,h=192.168.31.181,p='dts' --match-info "^(select)" --victims=all --busy-time 1 --interval 1 --no-version-check  --print --kill --match-user "dts"

在控制台的日志大致如下:

pt-kill 输出信息优化_pt-kill_03
pt-kill 输出信息优化_pt-kill_03

生产上,我们通常还会把kill的记录存到表里面,只要额外配置个库表,加点配置如下:

pt-kill u=dts,h=192.168.31.181,p='dts' --match-info "^(select)" --victims=all --busy-time 1 --interval 1 --no-version-check  --print --kill --log-dsn=h=192.168.31.181,u=dts,p='dts',P=3306,D=percona,t=kill_log --match-user "dts"

需要确保这个dsn上的kill_log表是存在的,建表语句如下:

代码语言:javascript
复制
 create database percona;
 
 use percona;
 
 CREATE TABLE `kill_log` (
  `kill_id` int unsigned NOT NULL AUTO_INCREMENT,
  `server_id` bigint NOT NULL DEFAULT '0',
  `timestamp` datetime DEFAULT NULL,
  `reason` text,
  `kill_error` text,
  `Id` bigint NOT NULL DEFAULT '0',
  `User` varchar(16) NOT NULL DEFAULT '',
  `Host` varchar(64) NOT NULL DEFAULT '',
  `db` varchar(64) DEFAULT NULL,
  `Command` varchar(16) NOT NULL DEFAULT '',
  `Time` int NOT NULL DEFAULT '0',
  `State` varchar(64) DEFAULT NULL,
  `Info` longtext,
  `Time_ms` bigint DEFAULT '0',
  PRIMARY KEY (`kill_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

kill_log表里面记录类似如下:

pt-kill 输出信息优化_pt-kill_04
pt-kill 输出信息优化_pt-kill_04

​经测试,发现 只有当存在 --kill 参数的情况下(即 --print --kill 或者单独的--kill),记录才会存到kill_log数据表里面。但是只要存在--print参数,不管是否有--kill参数,巡检记录都会输出到控制台日志。

对此,我们可以再修改下代码,在print的里面加上log的逻辑,如下(我把eval_error这个置为了ONLY_PRINT,便于数据库里查找):

代码语言:javascript
复制

修改后:
            if ( $o->get('print') ) {
               if ( $log ) {
                  log_to_table(
                     log        => $log,
                     query      => $query,
                     proclist   => $pl, 
                     columns    => \@processlist_columns,
                     eval_error => "ONLY_PRINT",
                  );   
               } 
            
                printf "# 检测时间: %s ,操作类型: %s ,Query_Id: %d ,用户名: %s ,客户端地址: %s ,库名: %s (%s %d sec) ,SQL明细: %s\n",
                    ts(time), ($o->get('kill-query') ||$o->get('kill')) ? 'KILL QUERY OR KILL' : 'ONLY_PRINT',
                    $query->{Id},$query->{User},$query->{Host},($query->{db} ? $query->{db} :'none'),($query->{Command} || 'NULL'), $query->{Time},
                   ($query->{Info} || 'NULL');
             }    
            if ( $o->get('query-id') ) {
                  my $fp = $qr->fingerprint($query->{'Info'});
                  my $chksm = Transformers::make_checksum($fp);
                  print "Query ID: 0x$chksm\n";
            }

有了数据后,我们就可以容易绘制grafana看板。

代码语言:javascript
复制
只print不查杀的记录:
SELECT
  -- a.timestamp,
  date_add( a.TIMESTAMP  , INTERVAL -8 hour) as "采样时间",
  a.server_id,
  a.user,
  a.db,
  a.host,
  a.info,
  a.`Time`,
  a.id,
  a.reason,
  a.State
FROM
  pt_kill_log AS a,
  pt_kill_log AS b
WHERE a.time =
  (SELECT
    MAX(`Time`)
  FROM
    pt_kill_log b
  WHERE a.id = b.id
    AND  a.`timestamp` BETWEEN DATE_FORMAT("$day", '%Y-%m-%d 00:00:00') AND DATE_FORMAT("$day", '%Y-%m-%d 23:59:59')
    AND a.kill_error = 'ONLY_PRINT'
    AND a.user != 'bi'
    )
GROUP BY a.id
ORDER BY a.`timestamp` DESC
-- LIMIT 1000




自动查杀的记录:

SELECT
  -- a.timestamp,
  date_add( a.TIMESTAMP  , INTERVAL -8 hour) as "采样时间",
  a.server_id,
  a.user,
  a.db,
  a.host,
  a.info,
  a.`Time`,
  a.id,
  a.reason,
  a.State
FROM
  pt_kill_log AS a,
  pt_kill_log AS b
WHERE a.time =
  (SELECT
    MAX(`Time`)
  FROM
    pt_kill_log b
  WHERE a.id = b.id
    AND  a.`timestamp` BETWEEN DATE_FORMAT("$day", '%Y-%m-%d 00:00:00') AND DATE_FORMAT("$day", '%Y-%m-%d 23:59:59')
    AND a.kill_error != 'ONLY_PRINT'
    AND a.user != 'bi'
    )
GROUP BY a.id
ORDER BY a.`timestamp` DESC
-- LIMIT 1000

最后:

在翻看代码的过程中,看到它是通过show full processlist 拿到数据后,在pt-kill内部处理的,而不是通过生产查询sql去查库,避免对数据库造成压力。 如果说不足的话,那就是还缺少一个IM告警的功能,这可能是为了工具的轻量化。

总的而言,pt-kill 可以满足日常的使用的,后续我们可以参考pt-kill的实现思路,用python重构一下增加IM告警能力。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档