5.6mysqldump gtid的一個小坑

故障現象

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同時導入


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章