默认情况下,pt-kill (3.3.1版本) 的执行记录如果是输出到log文件的话,日志里面是不会带上 库名、客户端地址的,类似如下:
我们可以简单修改下代码, 让其支持该属性的输出。
$ 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 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"
在控制台的日志大致如下:
生产上,我们通常还会把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表是存在的,建表语句如下:
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表里面记录类似如下:
经测试,发现 只有当存在 --kill 参数的情况下(即 --print --kill 或者单独的--kill),记录才会存到kill_log数据表里面。但是只要存在--print参数,不管是否有--kill参数,巡检记录都会输出到控制台日志。
在翻看代码的过程中,看到它是通过show full processlist 拿到数据后,在pt-kill内部处理的,而不是通过生产查询sql去查库,避免对数据库造成压力。 如果说不足的话,那就是还缺少一个IM告警的功能,这可能是为了工具的轻量化。
总的而言,pt-kill 可以满足日常的使用的,后续我们可以参考pt-kill的实现思路,用python重构一下增加IM告警能力。