共计 2354 个字符,预计需要花费 6 分钟才能阅读完成。
最近同事反映,在使用 pt-heartbeat 监控主从复制延迟的过程中,如果 master down 掉了,则 pt-heartbeat 则会连接失败,但会不断重试。
重试本无可厚非,毕竟从使用者的角度来说,希望 pt-heartbeat 能不断重试,直到重新连接上数据库。但是,他们发现,不断的重试会带来内存的缓慢增长。
重现
环境:
pt-heartbeat v2.2.19,MySQL 社区版 v5.6.31,Perl v5.10.1,RHEL 6.7,内存 500M
为了避免数据库启停对 pt-heartbeat 内存使用率的影响,故 MySQL 和 pt-heartbeat 分别运行在不同的主机上。
运行 pt-heartbeat
# pt-heartbeat –update -h 192.168.244.10 -u monitor -p monitor123 -D test –create-table
监控 pt-heartbeat 的内存使用率
获取 pid
# ps -ef |grep pt-heartbeat
root 1505 1471 0 19:13 pts/0 00:00:08 perl /usr/local/bin/pt-heartbeat --update -h 192.168.244.10 -u monitor -p monitor123 -D test --create-table
root 1563 1545 2 19:50 pts/3 00:00:00 grep pt-heartbeat
查看该进程的内存使用率
# top -p 1505
运行了 0:15.00(TIME+ 列),MEM 一直稳定在 3.3%
现关闭数据库
# service mysqld stop
刚才的 pt-heartbeat 命令不断输出以下信息
同样 CPU 时间后,MEM 增长到 4.4%,增长了 1%,考虑到内存 500M,该进程的内存占用增加了 5M,虽然不是很多,但考虑到进程的内存增加并没有停止的意思,这个现象还是要引起注意的。
同时,通过 pmap 命令,发现,0000000001331000 地址的 RSS 和 Dirry 也会增长,增长的速率是 4k/s
后来研究 pt-heartbeat 的源码,才发现代码有点 bug
my $tries = 2;
while (!$dbh && $tries-- ) {PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass,
join(', ', map {"$_=>$defaults->{$_}" } keys %$defaults ));
$dbh = eval {DBI->connect($cxn_string, $user, $pass, $defaults) };
if (!$dbh && $EVAL_ERROR ) {if ($EVAL_ERROR =~ m/locate DBD\/mysql/i ) {die "Cannot connect to MySQL because the Perl DBD::mysql module is "
. "not installed or not found. Run'perl -MDBD::mysql'to see "
. "the directories that Perl searches for DBD::mysql. If "
. "DBD::mysql is not installed, try:\n"
. " Debian/Ubuntu apt-get install libdbd-mysql-perl\n"
. " RHEL/CentOS yum install perl-DBD-MySQL\n"
. " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n";
}
elsif ($EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {PTDEBUG && _d('Going to try again without utf8 support');
delete $defaults->{mysql_enable_utf8};
}
if (!$tries ) {die $EVAL_ERROR;
}
}
}
以上代码摘自 get_dbh 函数,用于获取数据库的连接,如果获取失败,则重试 1 次,然后通过 die 函数抛异常退出。
但是,通过设置如下断点,发现当 $tries 为 0 时,if 函数里面的 PTDEBUG && _d(“$EVAL_ERROR”) 语句能执行,但 die 函数就是没有抛出异常,并退出脚本
PTDEBUG && _d($tries);
if (!$tries ) {PTDEBUG && _d("$EVAL_ERROR");
die $EVAL_ERROR; }
后来,将上述代码的最后一个 if 函数修改如下:
if (!$tries ) {die "test:$EVAL_ERROR";
}
再次测试
启动数据库
# service mysqld start
执行 pt-heartbeat 命令
# pt-heartbeat –update -h 192.168.244.10 -u monitor -p monitor123 -D test –create-table
停止数据库
# service mysqld stop
刚才执行的 pt-heartbeat 命令异常退出
“test:”就是加入的测试字符。
结论
很奇怪,只是单纯的 die $EVAL_ERROR 不会抛出异常,并退出脚本,但修改后的 die “test:$EVAL_ERROR” 却会退出脚本。
很显然,这确实是个 bug,不知道是不是与 perl 的版本有关。
很好奇,失败的连接如何导致内存的不断增长?
最后,给 percona 官方提了个 bug
https://bugs.launchpad.net/percona-toolkit/+bug/1629164
本文永久更新链接地址 :http://www.linuxidc.com/Linux/2016-10/135866.htm