最近同事反映,在使用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
以上所述是小編給大家介紹的當master down掉後,pt-heartbeat不斷重試會導致內存緩慢增長的原因及解決辦法,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!