mysql半同步复制“装了等于没装”的根本原因是插件名与版本不匹配:5.7用rpl_semi_sync_master/slave,8.0+改用semisync_master/slave,so文件名、加载时机及gtid下io线程重启顺序均需严格对应,否则rpl_semi_sync_master_status恒为off。

插件名和版本不匹配导致“装了等于没装”
MySQL 5.7 和 8.0+ 的半同步插件名完全不同,但错误不报在明面——INSTALL PLUGIN 执行成功,SELECT @@rpl_semi_sync_master_enabled 也返回 1,可 SHOW STATUS LIKE 'Rpl_semi_sync%' 里 Rpl_semi_sync_master_status 始终是 OFF。这是因为插件根本没加载成功,只是 MySQL 没抛硬错。
必须先查版本:SELECT VERSION();
- 5.7:主库用
rpl_semi_sync_master,从库用rpl_semi_sync_slave - 8.0+:主库用
semisync_master,从库用semisync_slave
SO 文件名也要对应:semisync_master.so(Linux)、semisync_master.dylib(macOS)、semisync_master.dll(Windows)。装完立刻验证:SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';,状态必须是 ACTIVE,否则后续所有配置都白搭。
GTID 环境下从库启用顺序错,半同步永远不生效
在已运行 GTID 复制的生产环境里,如果从库先 START SLAVE IO_THREAD,再装插件或设 rpl_semi_sync_slave_enabled = ON,半同步握手就错过了——因为握手发生在 IO 线程建立连接的最初几毫秒,插件没就位,主库就默认按异步走。
正确操作顺序(必须严格):
- 从库执行:
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';(8.0+ 换成semisync_slave) - 再执行:
SET GLOBAL rpl_semi_sync_slave_enabled = 1; - 最后重启 IO 线程:
STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
不能跳过重启步骤,也不能把 START SLAVE 放在最前。验证看从库的 Rpl_semi_sync_slave_status 是否为 ON,不是只看变量值。
超时参数设错引发业务抖动或静默降级
rpl_semi_sync_master_timeout 是生产环境中最容易误配的参数。设成 0 会卡死事务;设成 60000(60 秒)会让主库在从库失联时长时间阻塞;设成 100(0.1 秒)又太激进,网络毛刺就频繁降级。
建议值范围:2000~5000(2~5 秒),依据是主从间实测 RTT + 从库 relay log 写入延迟。上线前用 SELECT MASTER_POS_WAIT(..., 5) 在从库上压测追日志能力。
更关键的是监控降级行为:Rpl_semi_sync_master_no_times(降级次数)和 Rpl_semi_sync_master_off_times(因超时关闭次数)必须持续采集。这两个值只增不减,且不会自动恢复——除非有新事务触发重试,或手动重启 IO 线程。
AFTER_SYNC 模式没开,所谓“无损”就是假象
MySQL 5.7+ 默认的 rpl_semi_sync_master_wait_point = AFTER_COMMIT 仍是“有损”的:主库已提交、客户端已收到成功响应,但 binlog 还没发到从库,此时宕机,从库就丢了这个事务。
真正无损必须显式设为 AFTER_SYNC:SET GLOBAL rpl_semi_sync_master_wait_point = 'AFTER_SYNC';
这个参数不能写进 my.cnf,只能动态设置,且必须在插件启用后、主库开始接收写流量前完成。验证方式是查 SHOW VARIABLES LIKE 'rpl_semi_sync_master_wait_point';,输出必须是 AFTER_SYNC,不是 AFTER_COMMIT。
升级过程中最容易忽略这点:只改了插件和开关,忘了切 wait_point。一旦漏掉,所谓“无损升级”就只剩名字好听。











