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同时导入


你可能感兴趣的:(DB备份和恢复,DB故障处理案例,源码分析和C/C++学习)