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 线程被 SQLKILL终止;Group Replication 对旧成员连接在 5 分钟后停止。 replica_parallel_type移除,replica_parallel_workers最小值改为 1。- Performance:8.0 里能被优化掉的多余条件在后续版本不再被移除,这类查询性能明显下降(Bug #117907)。
- Replication chain 场景下
CREATE TABLE ... AS SELECT可能导致 binlog 不一致(Bug #37986380)。