最近同事反映,在使用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
以上所述是www.887551.com给大家介绍的当master down掉后,pt-heartbeat不断重试会导致内存缓慢增长的原因及解决办法,希望对大家有所帮助