引子
MySQLdump是非常重要的MySQL備份工具。然而在長年累月的使用過程中,TAOBAO多次出現了因MySQLdump意外終止而導致備份失敗的情況。
以下是我們經常遇到的問題:
1、Lost connection to MySQL Server at ‘reading initial communication packet’:
這個主要是因為DNS不穩定導致的。如果做了網絡隔離,MySQL處於一個相對安全的網絡環境,那麼開啟skip-name-resolve選項將會最大程度避免這個問題。
2、Lost connection to MySQL Server at ‘reading authorization packet’:
從MySQL獲取一個可用的連接是多次握手的結果。在多次握手的過程中,網絡波動會導致握手失敗。增加connect_timeout可以解決這個問題;然而增加connect_timeout並不能防止網絡故障的發生,反而會引起MySQL線程占用。最好的解決辦法是讓MySQLdump重新發起連接請求。
3、Lost connection to MySQL Server during query:
這個問題具備隨機性,而淘寶MySQL的應用場景決定了我們無法多次備份數據以便重現問題。
然而我們注意到這個問題一般會在兩種情況下會發生。一種是mysqldump **** | gzip ****;另外一種是MySQLdump **** > /nfs-file
注意,不管是gzip還是nfs都有一種特點,那就是它們影響了mysqldump的速度。從這個角度思考,是不是mysqldump從MySQL接受數據包的速度不夠快導致Lost connection to MySQL Server during query錯誤呢?
為了定位到問題,我搭建了一個測試環境:
[email protected]:3306
CREATE TABLE `test` (
`id` bigint(20) NOT NULL auto_increment,
`b` varchar(2000) default NULL,
`c` varchar(2000) default NULL,
`d` varchar(2000) default NULL,
`e` varchar(2000) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
insert into test(b,c,d,e) values (lpad(‘a’,1900,’b'), lpad(‘a’,1900,’b'), lpad(‘a’,1900,’b'), lpad(‘a’,1900,’b'));
多次復制數據使測試環境達到一定數據量。
192.168.0.2:
編寫一個c++程序
#include <stdio.h>
#include <MySQL.h>
using namespace std;
int main()
MySQL conn;
MySQL_RES *result;
MySQL_ROW row;
my_bool reconnect = 0;
MySQL_init(&conn);
mysql_options(&conn, MySQL_OPT_RECONNECT, &reconnect);
if(!MySQL_real_connect(&conn, “192.168.0.1″, “test”, “test”, “test”, 3306, NULL, 0))
fprintf(stderr, “Failed to connect to database: %s\n”, MySQL_error(&conn));
exit(0);
else
fprintf(stdout, “Success to connect\n”);
MySQL_query(&conn, “show variables like ‘%timeout%’”);
result = MySQL_use_result(&conn);
while(row=MySQL_fetch_row(result))
fprintf(stdout, “%-10s: %s\n”, row[0], row[1]);
MySQL_free_result(result);
fprintf(stderr, “\n”);
MySQL_query(&conn, “select SQL_NO_CACHE * from test.test”);
result = MySQL_use_result(&conn);
while((row=MySQL_fetch_row(result))!=NULL)
fprintf(stderr, “Error %d: %s\n”, mysql_errno(&conn), MySQL_error(&conn));
fprintf(stdout, “%s\n”, row[0]);
sleep(100);
fprintf(stderr, “Error %d: %s\n”, mysql_errno(&conn), MySQL_error(&conn));
MySQL_free_result(result);
MySQL_close(&conn);
return 1;
在這段代碼裡,sleep函數用來模擬NFS的網絡延遲和gzip的運算時間。執行一段時間之後,Lost connection to MySQL Server during query出現了,程序意外終止。在數據處理足夠快的情況下,又會是怎樣的結果?
將sleep的時間改為1,重新編譯後發現程序能夠完整跑完。根據上對net_write_timeout的解釋,我們可以發現,mysqldump處理數據過慢(NFS、gzip引起)會導致MySQL主動斷開連接,此時MySQLdump就會報Lost connection to MySQL Server during query錯誤。經過多次測試,確定這個錯誤是由於net_write_timeout設置過短引起。