半同步复制必须配合sync_binlog=1和innodb_flush_log_at_trx_commit=1,否则主库宕机仍可能丢事务;二者分别确保binlog和redo log强制落盘,缺一不可,虽带来10%–30%写入延迟,但可规避数据丢失风险。

半同步复制必须配 sync_binlog=1 和 innodb_flush_log_at_trx_commit=1
只开半同步但没调这两个参数,等于给主库装了刹车片却没踩油门——看起来安全,实际仍可能丢事务。
-
sync_binlog=1:确保每次事务提交都刷 binlog 到磁盘,否则主库宕机时未落盘的 binlog 会丢失,从库即使收到也无法重放 -
innodb_flush_log_at_trx_commit=1:保证 redo log 同步刷盘,避免 InnoDB 层数据已提交但未持久化 - 两者缺一不可:单独启用任一参数,都无法覆盖 WAL 链路中 binlog 和 redo 的双写缺口
- 性能影响真实存在:写入延迟会上升 10%–30%,但比异步复制下主库宕机丢数据的风险更可控
rpl_semi_sync_master_timeout 不要设成 0 或过大
这个超时值决定主库等从库 ACK 的忍耐极限,设错会导致要么频繁降级、要么卡死写入。
- 设为
0:主库永远等待,一旦从库网络抖动或 IO 卡顿,所有写请求阻塞 - 设为过大(如 30s):写入延迟不可控,业务超时风险陡增,且掩盖了从库真实健康问题
- 推荐值
10000(10 秒):兼顾多数网络波动场景,超时后自动退化为异步,保持可用性 - 配合监控
Rpl_semi_sync_master_yes_tx和Rpl_semi_sync_master_no_tx状态变量,判断降级频率是否异常升高
GTID 开启后必须禁用 sql_slave_skip_counter
用跳过错误的方式修复复制中断,在 GTID 模式下会直接破坏一致性,不是“绕过问题”,而是“制造新问题”。
- GTID 要求每个事务有唯一 ID 并严格按序执行,
sql_slave_skip_counter会跳过事务但不跳过 GTID,导致后续事务无法应用 - 常见报错:
Could not execute Write_rows_v1 event on table ...; Error_code: 1032; handler error HA_ERR_END_OF_FILE,本质是 GTID 集合断层 - 正确做法:发现不一致时,先查
SELECT @@global.gtid_executed;对比主从差异,再用SET GTID_NEXT='...'; BEGIN; COMMIT;注入空事务对齐,或重建从库 - 务必关闭
enforce_gtid_consistency=ON下的任何非 GTID 兼容操作(如 CREATE TEMPORARY TABLE)
不要依赖 Seconds_Behind_Master 判断实时一致性
这个字段只反映 SQL 线程落后 relay log 的秒数,和真实数据状态无关,尤其在并行复制或大事务场景下完全失真。
- 当从库正在重放一个耗时 5 分钟的大 UPDATE,
Seconds_Behind_Master可能显示 0,但该事务尚未提交,下游读取仍是旧值 - 并行复制开启后(
slave_parallel_workers > 0),SQL 线程可能已消费完 relay log,但 worker 线程还在执行中,Seconds_Behind_Master提前归零 - 真正关键的是
Slave_SQL_Running_State是否为executing,以及Retrieved_Gtid_Set和Executed_Gtid_Set的差值 - 生产环境建议用心跳表(如
mysql.heartbeat)+ 应用层打点,才能测出端到端写后读延迟











