编程 binlog 序号跨过 999999 后,半同步复制会静默变回异步

2026-10-24 21:04:20

MySQL 半同步复制在 binlog 序号跨过 999999 后会静默变成异步,9.4.0 才修复

现象:状态变量显示 ON,事务却不再等 ack

9.4.0(2025-07-22)的 Bugs Fixed / Replication 里有一条描述得很具体的修复:

Replication: During semisync replication, when the length of the binary log suffix exceeded six digits (.999999), so that the next log file became—for example—mysql-bin.1000000, the replication protocol unexpectedly changed from semisynchronous to asynchronous. Our thanks to Wuhao Cao and Karry Zhang and the team at Alibaba for the contribution. (Bug #115861, Bug #113813, Bug #37024069, Bug #36246779)

翻译过来:半同步复制运行期间,当 binlog 文件名后缀超过 6 位数字(越过 .999999),下一个文件变成 mysql-bin.1000000 这种形式时,复制协议会从半同步切换成异步。

真正难处理的是它“悄无声息”:

  • 没有任何报错,错误日志里看不到异常;
  • rpl_semi_sync_source_status 仍然显示 ON;
  • 但从这一刻起,主库提交事务不再等待 replica 的 ack。

也就是说,监控上看一切正常,实际已经变成异步复制。此时主库掉电或崩溃,最近一批已提交、尚未传到 replica 的事务就会丢失,而 RPO 的保证已经不存在了。这个问题的触发条件只是 binlog 文件序号自然地长到 7 位——业务量足够大、且运行时间足够长,总会撞上;低流量实例可能很久都遇不到。

插件命名:9.x 里是 semisync_source / semisync_replica

排查前先确认插件名。9.5.0 的 Deprecation/Removal 里,semisync_master 插件被移除,由 semisync_source 替代;semisync_slave 由 semisync_replica 替代(WL #16801)。所以在 9.x 上安装半同步插件应该用:

INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source';

再按 semisync_source / semisync_replica 的名字去找状态变量:rpl_semi_sync_source_status、Rpl_semi_sync_source_no_tx、Rpl_semi_sync_source_tx_wait_time_*、Rpl_semi_sync_source_clients 等。这些变量名在某些监控模板里还是旧名字,采集出来是空的却不报警,这也是“状态看起来正常”的常见来源。

本地复现思路

目标是把 binlog 序号推过 999999,让文件名出现 7 位序号。

  • 把 binlog basename 改成 mysql-bin(log_bin_basename 在实例启动时确定,配置写在 my.cnf 或启动参数里,不能在线修改,需要重启)。然后持续写入、等序号自然跨过 999999,或用 FLUSH BINARY LOGS 快速推进。
  • 也可以直接制造/改一个 7 位序号的 binlog 文件,再 FLUSH BINARY LOGS 让它成为当前文件(具体可行性需自行验证)。

复现后确认两点:

SHOW BINARY LOGS;                      -- 看文件名是否到 mysql-bin.1000000
SHOW STATUS LIKE 'Rpl_semi_sync_source%';
SHOW STATUS LIKE 'rpl_semi_sync_source_status';

反复提交事务,观察 Rpl_semi_sync_source_no_tx、Rpl_semi_sync_source_tx_wait_time_* 是否还在增长。如果写入在继续、这些计数器却不动,而 rpl_semi_sync_source_status 仍是 ON,就是本文描述的情况。具体触发边界以发布说明为准,复现细节需自行验证。

监控与验收

  • 每 5 分钟执行一次 SHOW BINARY LOGS,取最大文件名的数字后缀位数;>= 7 就要警惕。
  • 采样 semi-sync 状态变量:存在写入时,Rpl_semi_sync_source_no_tx 或 Rpl_semi_sync_source_tx_wait_time_* 应该增长;有写入但长时间完全不变,作为告警条件。
  • 不要只依赖 rpl_semi_sync_source_status,它在这个 bug 下没有参考价值。
  • 压测里做 A/B 对比:同一负载下开启半同步与关闭半同步的提交延迟。正常半同步应该有可测量的延迟差;退化后这个差值消失,提交延迟贴近纯异步。

升级与规避

9.4.0 起该 bug 已修复。升级前若只能停留在旧版本,至少要加两条告警:binlog 文件序号位数 >= 7;以及有写入时 Rpl_semi_sync_source_no_tx 不再增长。

升级到 9.5.0 还要一并评估默认值改动:gtid_mode 默认 ON,CHANGE REPLICATION SOURCE TO 的 SOURCE_SSL 默认 1,group_replication_ssl_mode 默认 REQUIRED,group_replication_recovery_use_ssl 默认 ON。这些会把原本隐式关闭的 TLS 变成默认开启,证书链和端口要先验证。

同批次其它值得留意

  • 新增错误码 ER_GRP_RPL_APPLIER_THD_KILLED,用于区分 applier 线程被 SQL KILL 终止;Group Replication 对旧成员连接在 5 分钟后停止。
  • replica_parallel_type 移除,replica_parallel_workers 最小值改为 1。
  • Performance:8.0 里能被优化掉的多余条件在后续版本不再被移除,这类查询性能明显下降(Bug #117907)。
  • Replication chain 场景下 CREATE TABLE ... AS SELECT 可能导致 binlog 不一致(Bug #37986380)。
复制全文 生成海报 MySQL 复制 故障排查

推荐文章

程序员茄子在线接单