MySQLPump是MySQL官方提供的一个用于备份和恢复MySQL数据库的工具。它于MySQL 5.7.8版本中首次引入,旨在提供一种快速、可靠且高效的备份和恢复解决方案。MySQL Pump首次支持了并行导出、压缩导出
,可以利用多核CPU来提高备份能力,在效率上要比mysqldump要高很多。mysqlpump同mysqldump一样导出的文件以SQL语句的形式
。这篇文章主要分享一下在使用mysqlpump导出时加上--set-gtid-purged参数遇到的bug。
各位大佬都知道在开启gtid全局事务标识符的MySQL主从环境中,如果导入的数据是通过mysqldump或者mysqlpump在其他开启gtid的实例上导出的,那么就必须设置--set-gtid-purged参数,如果不设置--set-gtid-purged参数,那么默认通过mysqldump或者mysqlpump导出的数据进行导入时,从库是没有数据的,因为导出的SQL文件中会默认加上@@SESSION.SQL_LOG_BIN= 0
,这就非常鸡肋。。。。那先来聊聊SQL_LOG_BIN参数的作用,以及在使用mysqldump或者mysqlpump导出时不加--set-gtid-purged参数,导出的SQL文件是怎么体现SQL_LOG_BIN参数的。
SQL_LOG_BIN参数介绍:
生效范围 | Session(注:只支持会话级别) |
默认值 | ON |
可以设置的值 | OFF | ON |
作用 | 对当前的会话是否记录到二进制日志中,默认值为ON,也就是当前会话的所有的操作都会记录到二进制日志,记录二进制日志是必须的,因为恢复、主从复制等场景都需要记录到二进制日志中。如果关闭,也就是设置为OFF,那么在这个会话的操作都不记录到二进制日志中。 |
在开启gtid的实例上使用mysqldump导出数据,查看SQL文件中对SQL_LOG_BIN参数的定义:
[root@ha1 backup]# mysqldump -uroot -p123456 --single-transaction --master-data=2 --flush-logs --flush-privileges --routines --events --all-databases --log-error=mysqldump_liudbwycs_3306_err.log --skip-add-locks --socket=/liu_data/mysql5.7/data/3306/liu.sock > mysqldump_liudbwycs_3306.sql
可以看到使用mysqldump不管在5.7还是8.0中都会设置SQL_LOG_BIN= 0,也就是说导入的数据都不会写入到二进制日志中
在开启gtid的实例上使用mysqlpump导出数据,查看SQL文件中对SQL_LOG_BIN参数的定义:
[root@ha1 backup]# mysqlpump -uroot -p123456 --single-transaction --users --default-parallelism=2 --all-databases --exclude-databases=mysql --log-error-file=mysqlpump_liudbwycs_3306_err.log --extended-insert=10000 --socket=/liu_data/mysql5.7/data/3306/liu.sock > mysqlpump_liudbwycs_3306.sql
同样的使用mysqlpump不管在5.7还是8.0中都会设置SQL_LOG_BIN= 0,也就是说导入的数据都不会写入到二进制日志中
通过上面的截图,已经非常清楚了,使用mysqldump或者mysqlpump导出的数据进行导入的话都不会写到二进制日志,这个在单机的MySQL实例上导入没有问题,但在是主从复制或者MGR等依赖主从复制环境的架构中是个非常坑的问题 ,因为从库就是读取主库的二进制,现在导入的数据都不写二进制日志了,那么从库还复制啥子数据
,当然MySQL也提供了解决办法,就是在使用mysqldump或者mysqlpump导出时加上--set-gtid-purged=OFF参数(两个导出工具都支持--set-gtid-purged参数,并且功能都是一样的),关于这个参数的介绍如下:
mysqldump中--set-gtid-purged参数:
默认值 | AUTO |
可以设置的值 | OFF |
作用 | 用于使用基于 GTID 的复制的实例(gtid_mode=ON)。它控制是否在导出文件中包含 SET @@GLOBAL.gtid_purged 语句,该语句更新在重新加载导出文件的目标服务器上 gtid_purged 的值, 将源服务器的 gtid_executed 系统变量中的 GTID 集合添加到目标服务器中。gtid_purged 保存了服务器上所有已执行事务的 GTID,但这些事务不再存在于任何二进制日志文件中。因此,mysqldump 会将源服务器上已执行事务的 GTID 添加到导出文件中,以便目标服务器记录这些事务为已应用,尽管它们不在目标服务器的二进制日志中。--set-gtid-purged 还控制是否在导出文件中包含 SET @@SESSION.sql_log_bin=0 语句,该语句在重新加载导出文件时禁用二进制日志记录。此语句会防止在执行导出文件中的事务时生成和分配新的 GTID,从而确保事务使用原始的 GTID。 |
mysqlpump中--set-gtid-purged参数:
默认值 | AUTO |
可以设置的值 | OFF |
作用 | 此选项通过指示是否将 SET @@GLOBAL.gtid_purged 语句添加到输出中,从而控制写入转储文件的全局事务ID(GTID)信息。此选项还会再SQL文件中写入一条禁用二进制日志的SET @@SESSION.sql_log_bin=0 语句。 |
从参数介绍可以看出,不管是mysqldump还是mysqlpump在使用--set-gtid-purged=OFF参数时都会将设置gtid的语句SET @@GLOBAL.GTID_PURGED和SET @@SESSION.SQL_LOG_BIN取消掉
,所以加上--set-gtid-purged=OFF参数可以解决两个问题:
解决的问题一:如果导入的主库实例已经存在了gtid全局事务标识符,那么导出开启gtid的实例时就必须加上--set-gtid-purged=OFF,因为不加的话直接导出的SQL文件中会有设置SET @@GLOBAL.GTID_PURGED这行,就会导致报错:GTID_PURGED can only be set when GTID_EXECUTED is empty。
解决的问题二:导入的主库实例下面还挂有从库,那么导出开启gtid的实例时就必须加上--set-gtid-purged=OFF,因为不加的话直接导出的SQL文件中会有设置SET @@SESSION.SQL_LOG_BIN=0这行,就会导致导入的数据不写二进制日志,没有二进制日志从库也就没有数据了
那么继续演示下,在开启gtid的实例上通过mysqldump或者mysqlpump导出时加上--set-gtid-purged=OFF参数,演示如下:
在开启gtid的实例上使用mysqldump导出数据加上--set-gtid-purged=OFF,查看SQL文件:
[root@ha1 backup]# mysqldump -uroot -p123456 --set-gtid-purged=OFF --single-transaction --master-data=2 --flush-logs --flush-privileges --routines --events --all-databases --log-error=mysqldump_liudbwycs_3306_err.log --skip-add-locks --socket=/liu_data/mysql5.7/data/3306/liu.sock > mysqldump_liudbwycs_3306.sql
可以看到使用mysqldump不管在5.7还是8.0中加上--set-gtid-purged=OFF参数,不仅会去掉SET @@GLOBAL.GTID_PURGED、SET @@MYSQLDUMP_TEMP_LOG_BIN,还会去掉SET @@SESSION.SQL_LOG_BIN
在开启gtid的实例上使用mysqlpump导出数据加上--set-gtid-purged=OFF,查看SQL文件:
[root@ha1 backup]# mysqlpump -uroot -p123456 --set-gtid-purged=OFF --single-transaction --users --default-parallelism=2 --all-databases --exclude-databases=mysql --log-error-file=mysqlpump_liudbwycs_3306_err.log --extended-insert=10000 --socket=/liu_data/mysql5.7/data/3306/liu.sock > mysqlpump_liudbwycs_3306.sql
可以看到使用mysqldump不管在5.7还是8.0中加上--set-gtid-purged=OFF参数,只会去掉SET @@GLOBAL.GTID_PURGED,不会去掉SET @@SESSION.SQL_LOG_BIN,但官方文章中明确标注mysqldump加上--set-gtid-purged=OFF参数是会去掉SET @@SESSION.SQL_LOG_BIN的,但实际并没有去掉,所以这是这个工具的一个bug。
这也就是为啥使用mysqlpump导出开启gtid实例的数据,并且我也已经加上--set-gtid-purged=OFF参数了,但导入主库后,从库还没有数据的原因。
mysqlpump这个bug虽然很小,但对于在开启gtid全局事务标识符的主从环境中使用mysqlpump导出的数据进行导入来说是非常严重的,导致了主从数据不一致。目前这个bug至少在5.7和8.0版本都存在,使用这两个版本的小伙伴们可以避坑一下,也希望MySQL在之后的大版本中进行优化😳