半同步复制的真相:千万别被“增强版”三个字误导

先给出核心结论:半同步复制这个功能,尽管名称中带有“同步”二字,但实际上无法实现数据零丢失。它的极限是什么?最多丢失一个事务。至于业界流传的所谓“增强版”,说白了,就是MySQL 5.7+版本中AFTER_SYNC模式、GTID、多从库ACK以及低超时配置的组合运用。这四个要素缺一不可,缺少任何一个,效果都会大打折扣。
为什么SHOW STATUS里总是显示OFF?别只盯着插件状态
很多用户遇到Rpl_semi_sync_*_status始终为OFF的情况,第一反应是插件未安装。其实不然,问题往往出在线程层面。半同步复制在从库端,只有在IO线程启动时才会完成初始化。仅仅执行一句SET GLOBAL rpl_semi_sync_sla ve_enabled = 1,根本起不到作用。
- 必须显式重启IO线程:先执行
STOP SLA VE IO_THREAD;,再执行START SLA VE IO_THREAD;,这才是正确的操作步骤。 - MySQL 8.0.26及以上版本,插件名和参数名已发生变化:需要使用
semisync_replica.so以及对应的rpl_semi_sync_replica。如果继续混用旧版sla ve名称,插件状态虽然显示ACTIVE,但实际上不会正常工作。 - 通过
SELECT @@plugin_dir确认插件路径后,务必检查对应的.so文件是否真实存在。Linux环境下大小写敏感,扩展名必须是.so,忽略任何细节都可能导致问题。 - 不要忘记防火墙配置。不仅主库3306端口的初始连接要放行,从库IP的双向TCP ACK流量也必须能够通过。很多网络层面的半同步降级,根源就在此处。
AFTER_SYNC:这个参数决定数据安全边界
rpl_semi_sync_master_wait_point这个参数,决定了主库在事务生命周期的哪个节点等待ACK。这一配置划清了“已提交即已落盘”的安全边界。
AFTER_COMMIT(MySQL 5.6及更早版本的默认值):主库先提交事务,再发送binlog。一旦主库在发送binlog之前崩溃,所有已提交但尚未发出的事务,将直接丢失。AFTER_SYNC(MySQL 5.7+版本的默认值):执行顺序完全反转。主库先写入binlog,然后等待至少一个从库将日志写入relay log,最后才提交事务。这样一来,任何已提交的事务,必定存在于至少一个从库的relay log中。这才是真正的安全保障底线。- 设置命令非常简单:8.0.26及以上版本使用
SET GLOBAL rpl_semi_sync_source_wait_point = 'AFTER_SYNC';,更早版本使用SET GLOBAL rpl_semi_sync_master_wait_point = 'AFTER_SYNC';。需要注意的是,此设置仅影响后续连接的新事务,对当前正在运行的事务不会产生作用。
关键参数:不要用默认值凑合
MySQL的默认参数,更多是为了兼容性而做出的妥协。生产环境,尤其是金融场景,必须手动收紧,不要指望开箱即用。
rpl_semi_sync_master_timeout = 1000:单位是毫秒。不要使用默认的10000(10秒)。超时一旦到达就降级为异步,1秒是平衡安全性与可用性的合理底线。rpl_semi_sync_master_wait_for_sla ve_count = 2:强制等待至少两个从库返回ACK。这样配置,即使一个从库网络出现波动,也不会立即触发降级。单点依赖过于脆弱。- GTID必须开启:
gtid_mode = ON配合enforce_gtid_consistency = ON。否则主从切换时,位点一旦混乱,数据一致性就无法保障。 - 在主库的
my.cnf配置文件中,记得将rpl_semi_sync_source_enabled = 1(8.0.26及以上版本)或rpl_semi_sync_master_enabled = 1(≤8.0.25版本)固化写入,不要每次手动设置。
监控指标:不要只看ON/OFF,要关注降级频率
一个常见的认知误区是:字面状态显示为ON,就以为所有事务都走半同步路径。实际上,半同步随时可能自动降级为异步。状态ON只代表插件已加载,并不代表每条事务都走了完整流程。
- 真正需要关注的是这两个计数器:
Rpl_semi_sync_master_no_times(降级次数)和Rpl_semi_sync_master_no_tx(降级事务数)。如果这两个数值持续增长,说明问题不在于配置,而在于网络延迟或从库relay log写入速度过慢——这是基础设施层面的瓶颈。 Rpl_semi_sync_master_clients这个值,应该稳定保持在2或以上。如果它频繁归零,就需要检查从库的IO线程是否存在异常中断,或者插件是否被意外卸载。- 从MySQL 9.6.0版本开始,引入了
container_aware启动选项。如果数据库运行在容器环境中,务必启用此选项。否则ACK包可能因为网络命名空间隔离而失败,这个问题在云原生环境下越来越常见。
说到底,真正有技术挑战的,不是把这些配置“配通”。而是让AFTER_SYNC在每一笔事务中都稳定生效、让两个从库的ACK在1秒内可靠地回传、让GTID在主从切换时不产生任何跳变。这几个环节环环相扣,任何一环出现松动,所谓的“增强版”就会退化为普通的半同步复制,数据零丢失的目标也就成了空谈。
