必须实时验证rpl_semi_sync_master_status为on且rpl_semi_sync_master_no_tx为0,同时确认rpl_semi_sync_master_clients>0、从库io线程重启生效、主从插件正确安装,才能确保半同步真正起作用而非形同虚设。

MySQL主从切换无法做到绝对零丢失,但只要确认半同步真正生效、选对从库、主库日志落盘可靠,就能把丢失风险压到极低——关键不是“开了没开”,而是“它此刻有没有在起作用”。
怎么确认半同步真在起作用,而不是形同虚设
很多团队只执行了SET GLOBAL rpl_semi_sync_master_enabled = 1就以为安全了,结果切主时发现事务已降级提交。必须实时验证状态,而非只看变量值:
-
SHOW STATUS LIKE 'Rpl_semi_sync%'中,Rpl_semi_sync_master_status必须为ON,且Rpl_semi_sync_master_no_tx应长期为0;非零说明已有事务退化为异步提交 - 从库必须执行
STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;(不是START SLAVE),否则插件不响应、无法上报 ACK - 主库插件名是
rpl_semi_sync_master,从库是rpl_semi_sync_slave;装反或漏装会导致Rpl_semi_sync_master_clients = 0 - 检查插件文件是否存在:
ls -l $(mysql -Nse "SELECT @@plugin_dir")/semisync_*.so;MySQL 5.7 以下需手动补全,注意架构(x86_64/aarch64)匹配
切主前必须验证的两个位点是否真正对齐
只看Seconds_Behind_Master = 0是危险的——SQL 线程可能卡在大事务里,IO 已追平但实际没执行。真正要确认的是:
-
Read_Master_Log_Pos == Exec_Master_Log_Pos:表示从库不仅收到了 binlog,而且已全部执行完毕 -
Slave_SQL_Running_State显示Slave has read all relay log,而非Reading event from the relay log - 用
mysqlbinlog对比主库最新 binlog position 和从库SHOW SLAVE STATUS\G中的Read_Master_Log_Pos,差值过大说明 IO 延迟高,半同步容易超时退化
主库自身必须配齐日志落盘底线参数
即使半同步生效,若主库崩溃时 binlog 或 redo 日志还没刷盘,照样丢已提交事务。以下三项必须同时启用:
-
sync_binlog = 1:每次事务提交都强制刷 binlog 到磁盘,否则主库宕机后未刷盘的 binlog 永久消失 -
innodb_flush_log_at_trx_commit = 1:每次事务提交都刷 redo log 到磁盘,保障 InnoDB 层不丢事务 -
rpl_semi_sync_master_timeout = 10000:设为 10 秒,太短(如 1000)会导致网络抖动频繁退化,太长(如 60000)会让主库响应卡顿
为什么 GTID 模式下仍可能丢数据,以及怎么防
GTID 并不自动防丢,错误用法反而加剧风险:
- 手动执行
CHANGE MASTER TO MASTER_AUTO_POSITION = 0后指定MASTER_LOG_FILE和MASTER_LOG_POS,若位置点落在某个 GTID 事务中间,MySQL 会跳过整个 GTID,导致永久丢失 -
sql_slave_skip_counter在 GTID 模式下禁用;遇到 1062 错误应改用SET GTID_NEXT='xxx'; BEGIN; COMMIT;注入空事务跳过 - 切主前务必确认从库包含所有应有 GTID:
SELECT * FROM performance_schema.replication_applier_status_by_coordinator; - 从库
relay_log_purge = OFF看似安全,实则易引发磁盘爆满导致 SQL thread halt,错误日志只报No space left on device,难定位
最容易被忽略的点是:半同步只保证“至少一个从库收到并写入 relay log”,不保证已执行、不保证已提交。所以“选对从库”比“开了半同步”重要得多——那个Exec_Master_Log_Pos最接近主库File/Position的从库,才是该提拔的对象。











