美文网首页
MySQL:备库可以设置sync_binlog非1吗?

MySQL:备库可以设置sync_binlog非1吗?

作者: 轻松的鱼 | 来源:发表于2023-12-17 14:37 被阅读0次

都知道MySQL主库必须设置sync_binlog=1,防止断电丢失binlog,crash recovery 过程丢失数据。那么作为备库可以例外吗?

我们的第一反应当然是不行,既然主库会丢数据,备库自然一样。但其实不然,备库丢了数据是可以重新从主库上复制的,只要这个复制的位置和备库本身数据的位置一致就OK了,本文探讨的就是这个问题,它们能一致吗?

为了更好的说明这个问题,下面赘述一下相关的知识点:

  1. InnoDB的二阶段提交中,prepare 阶段写 redo log,commit 阶段写 binlog,crash recovery 时保证:
    • 所有已提交事务的 binlog 一定存在
    • 所有未提交事务一定不记录 binlog
  2. 备库设置 relay_log_info_repository = table 时,slave_relay_log_info(即备库回放位置)的更新与relay log回放的SQL在同一个事务中提交
  3. GTID 持久化在 binlog 中,备库在某些条件下启动复制时会从 Executed_Gtid_Set 开始到主库复制数据

根据以上三点,备库如果设置 sync_binlog 不为1,在做 crash recovery 时的情况是:

  • 对于已经提交但数据页未落盘的事务(TRX_COMMITTED_IN_MEMORY、TRX_NOT_STARTED),如果 binlog 未落盘,事务会重做,数据将比 binlog 多,slave_relay_log_info 表记录的复制位置也将领先 Executed_Gtid_Set
  • 对于 TRX_PREPARED 状态的事务,由于binlog 未刷盘,recovery 时会回滚事务,数据与binlog 是一致的,slave_relay_log_info 表记录的复制位置等于 Executed_Gtid_Set

如果备库断电恢复后,启动复制时用的位置由 slave_relay_log_info 决定,则备库数据还是能正常复制数据,并且能与主库保持一致,只是 GTID 会出现跳号。反之如果由 Executed_Gtid_Set 决定,则备库复制会因为重复回放事务而报错,需要进行修复。下面设计一个实验来进行验证。

实验过程

  1. 备库参数设置如下,主库用工具并发写入数据(这里用的 mysqlslap),然后备库强制关机(reboot -f)
sync_binlog = 1000
innodb_flush_log_at_trx_commit = 1
relay_log_info_repository = table  ##slave_relay_log_info 表为 innodb 表
relay_log_recovery = on
gtid_mode = on
  1. 备库服务器开机后重启MySQL,查看的信息如下
show master status 输出的 Executed_Gtid_Set 如下:
fb9b7d78-6eb5-11ec-985a-0242ac101704:1-167216 

mysql> select * from slave_relay_log_info\G
*************************** 1. row ***************************
  Number_of_lines: 7
   Relay_log_name: ./localhost-relay-bin.000004
    Relay_log_pos: 4
  Master_log_name: mysql-bin.000001
   Master_log_pos: 48159613
        Sql_delay: 0
Number_of_workers: 0
               Id: 1
     Channel_name:
1 row in set (0.00 sec)

说明从库的数据确实回放到了 mysql-bin.000001:48159613,对应的GTID为:fb9b7d78-6eb5-11ec-985a-0242ac101704:167222
只是从库的 binlog 有丢失,GTID为:fb9b7d78-6eb5-11ec-985a-0242ac101704:1-167216

...
SET @@SESSION.GTID_NEXT= 'fb9b7d78-6eb5-11ec-985a-0242ac101704:167222'/*!*/;
...
### INSERT INTO `mysqlslap`.`t`
### SET
###   @1=167216 /* INT meta=0 nullable=0 is_null=0 */
# at 48159586
#220407 14:10:34 server id 123456  end_log_pos 48159613         Xid = 169239
COMMIT/*!*/;
# at 48159613
...

从库已经有167222事务对应的数据:

mysql> select * from t where id=167216;
+--------+
| id     |
+--------+
| 167216 |
+--------+
1 row in set (0.00 sec)
  1. 接下来备库启动复制
    error log 显示的起始位置和 slave_relay_log_info 内容一样,从主库的 mysql-bin.000001:48159613 开始,对应 GTID 为 167222+1:

Slave I/O thread: Start asynchronous replication to master 'repl@10.186.61.32:3308' in log 'mysql-bin.000001' at position 48159613

但接下来 SQL 线程报错位置却是 mysql-bin.000001:48158146,比开始位置还靠前,这个位置对应的 GTID 为 167217(即167216+1):

2022-04-07T06:33:18.611181-00:00 4 [ERROR] Slave SQL for channel '': Could not execute Write_rows event on table mysqlslap.t; Duplicate entry '167212' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000001, end_log_pos 48158146, Error_code: 1062

而且解析从库 relay log(因为设置了 relay_log_recovery = on,启动复制时会丢弃旧的未 relay log 重新到主库取 binlog),第一个事务也是 SET @@SESSION.GTID_NEXT= 'fb9b7d78-6eb5-11ec-985a-0242ac101704:167217'/*!*/;,而不是 167223。这说明了启动复制的位置并不是 slave_relay_log_info 记录的位置,而是从库的 GTID。

  1. 重复以上测试,在启动从库复制前执行 change master to master_auto_position=0; 这回不报错,是从 167223 这个GTID开始复制数据,从库 GTID 会出现跳号:
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                                           |
+------------------+----------+--------------+------------------+-------------------------------------------------------------+
| mysql-bin.000006 |  9976340 |              |                  | fb9b7d78-6eb5-11ec-985a-0242ac101704:1-167216:167223-200670 |
+------------------+----------+--------------+------------------+-------------------------------------------------------------+
1 row in set (0.01 sec)

结论

从库 sync_binlog 设置不为1,发生断电时,会丢失 binlog,因为 GTID 持久化在 binlog 中,因此也会丢失 GTID,但是数据和 slave_relay_log_info 表中保存的SQL线程回放位置一致。此时:

  • 如果 master_auto_position=0,则从库重启复制时可以从正确的位置开始复制数据,从而与主库数据一致。不过从库会产生 GTID 跳号;
  • 如果 master_auto_position=1,则从库重启复制时会从 GTID 处开始复制数据,由于 GTID 有丢失,所以会重复回放事务,产生报错。

相关文章

  • MySQL主从复制实战

    一、主数据库设置 主mysql增加如下配置到[msqld] 优化参数解释: sync_binlog默认值是 0,不...

  • MySQL binlog 和主从复制

    项目的架构是:生产的mysql库有一个备库,备库不对外提供服务,唯一的目的是备份生产mysql库的数据 MySQL...

  • Mysql主从配置

    mysql主备配置的时候,这时主添加数据,备库未更新,这时有查询进来,查询到了备库。如何解决。可以sql语句强行走...

  • MySQL主备

    MySQL主备数据流转流程 备库B和主库A维持了一个长连接1、在备库 B 上通过 change master 命令...

  • 架构师训练营第6周学习总结

    1.分布式数据库 1,1:MySQL 主从复制(写入主服务器,mysql binlog记录操作日志,备库数据库有个...

  • mysql开启外网访问权限

    1:设置mysql的配置文件 重启mysql:service mysql restart 2:登录mysql数据库...

  • Mysql分库分表备份方法实现

    1.mysqldump工具介绍 mysqldump命令是MySQL数据库自带的一个备份命令,它支持数据库全备也可以...

  • MySQL与Redis主从复制

    MySQL主备数据一致性 整体流程 第一阶段在备库上通过 change master 命令,设置主库的 IP、端口...

  • Mac 环境下学习mysql

    连接数据库 1、系统偏好设置 > MySQL > start MySQL server,开启本机的MySQL数据...

  • MySQL Replication

    MySQL没有增量备份机制 MySQL提供了主从备份机制以实现热备 双机热备需服务器版本高于3.2 从库版本可以高...

网友评论

      本文标题:MySQL:备库可以设置sync_binlog非1吗?

      本文链接:https://www.haomeiwen.com/subject/reqogdtx.html