故障現象
Master-slave+GTID架構下,從master導入5.6的備份,發現數據沒有同步到從庫,通過查看備份文件內容,發現sql_log_bin被設置爲0從而在導入時禁用了binlog引起。
/*!40101 SET@OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET@OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
SET@MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET@@SESSION.SQL_LOG_BIN= 0;
-- GTID state atthe beginning of the backup
原因分析
Mysqldump版本要求:5.6對應的mysqldump
那麼很奇怪,mysqldump爲何會莫名其妙地加上這幾句命令呢,通過測試我發現
場景1
mysqldump -hXXXXXX -P3306 -uucloudbackup -pXXXXX--all-databases >/tmp/xx.sql
head -20/tmp/xx.sql
-- MySQL dump10.13.ucloudrel1 Distrib5.6.20-ucloudrel1, for Linux (x86_64)
--
-- Host: 10.9.160.127 Database:
--------------------------------------------------------
-- Serverversion 5.6.20-ucloudrel1-log
/*!40101 SET@OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET@OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET@OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SETNAMES utf8 */;
/*!40103 SET@OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SETTIME_ZONE='+00:00' */;
/*!40014 SET@OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS,FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET@OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET@OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
SET@MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET@@SESSION.SQL_LOG_BIN= 0;
場景2
mysqldump -hXXXXXX -P3306 -uucloudbackup –pXXXXX--all-databases --set-gtid-purged=OFF>/tmp/xx1.sql
head -20/tmp/xx1.sql
-- MySQL dump10.13.ucloudrel1 Distrib5.6.20-ucloudrel1, for Linux (x86_64)
--
-- Host: 10.9.160.127 Database:
--------------------------------------------------------
-- Serverversion 5.6.20-ucloudrel1-log
/*!40101 SET@OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET@OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET@OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SETNAMES utf8 */;
/*!40103 SET@OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SETTIME_ZONE='+00:00' */;
/*!40014 SET@OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS,FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET@OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET@OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- CurrentDatabase: `mysql`
現象總結
假如在開了gtid複製的情況下,默認mysqldump會記錄GTID_PURGED信息,但同時它還會引入一個其他動作,即輸出以下幾行
SET @MYSQLDUMP_TEMP_LOG_BIN= @@SESSION.SQL_LOG_BIN;
SET@@SESSION.SQL_LOG_BIN= 0;
假如mysqldump時設置了--set-gtid-purged=OFF,則在備份文件中不會打印有以上信息;
源碼分析
帶着這樣的困惑我去翻閱了下mysqldump客戶端源碼,發現了由函數set_session_binlog控制是否打印binlog信息
static voidset_session_binlog(my_bool flag)
{
static my_bool is_binlog_disabled= FALSE;
if (!flag && !is_binlog_disabled)
{
fprintf(md_result_file,
"SET @MYSQLDUMP_TEMP_LOG_BIN =@@SESSION.SQL_LOG_BIN;\n");
fprintf(md_result_file, "SET@@SESSION.SQL_LOG_BIN= 0;\n");
is_binlog_disabled= 1;
}
else if (flag && is_binlog_disabled)
{
fprintf(md_result_file,
"SET @@SESSION.SQL_LOG_BIN =@MYSQLDUMP_TEMP_LOG_BIN;\n");
is_binlog_disabled= 0;
}
}
從源碼不難猜測:也就是說如果輸入參數flag爲0的話則會在mysqldump開始打印SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN等信息,調用後將is_binlog_disabled變量置爲1,並在mysqldump結束時傳入flag=1,打印SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN使得sql_log_bin參數恢復爲原來的值。
通過函數process_set_gtid_purged來判斷gtid信息
/**
This function processes theopt_set_gtid_purged option.
This function also calls set_session_binlog()function before
setting the SET @@GLOBAL.GTID_PURGED in theoutput.
@param[in] mysql_con the connection to the server
@retval FALSE successful according to the value
ofopt_set_gtid_purged.
@retval TRUE fail.
*/
if(gtid_mode_val && strcmp(gtid_mode_val, "OFF"))
{
/*
For any gtid_mode !=OFF and irrespectiveof --set-gtid-purged
being AUTO or ON, add GTID_PURGED in the output.
*/
if (opt_databases || !opt_alldbs ||!opt_dump_triggers
|| !opt_routines || !opt_events)
{
fprintf(stderr,"Warning: A partialdump from a server that has GTIDs will "
"by default includethe GTIDs of all transactions, even "
"those that changedsuppressed parts of the database. If "
"you don't want torestore GTIDs, pass "
"--set-gtid-purged=OFF. To make a complete dump, pass "
"--all-databases--triggers --routines --events. \n");
}
set_session_binlog(FALSE);
在main函數的部分可看到備份的末尾位置都會調用
/*
if --set-gtid-purged,restore binlog at the end of the session
if required.
*/
set_session_binlog(TRUE);
因爲如果gtid打開的話,這時會走set_session_binlog函數的else分支,從而使sql_log_bin還原爲初始值;如果gtid沒有打開的話,is_binlog_disabled值必爲0,則調用這個函數,實際上什麼都沒做。所以,dump結尾部分都會調用set_session_binlog(TRUE)
解決方案
1 GTID+master-slave架構下,如果備份文件已經禁用了sql_log_bin,導入一個備份文件時需要將這幾行去掉,總共三行
SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;
SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;
2 分別導入兩遍,master和slave同時導入