☰
半同步复制:数据安全和服务可用之间怎么权衡
2026/10/17 10:45:09 网站建设 项目流程
个人主页: > for_ever_love__ <(欢迎各位大佬莅临😊)
其他栏目: > 大模型开发从0到1 <
其他栏目: > iOS项目总结大全 <
其他栏目: > 我想学python了 <
其他栏目: > iOS UI <

文章目录

  • 半同步复制:数据安全和服务可用之间怎么权衡
    • 一、三种复制方式对比
      • 异步复制丢失数据的场景
    • 二、半同步的原理
    • 三、怎么配置
      • 3.1 安装插件
      • 3.2 开启
      • 3.3 配置文件(永久)
    • 四、关键参数
      • 4.1 `rpl_semi_sync_master_timeout`
      • 4.2 `rpl_semi_sync_master_wait_no_slave`
      • 4.3 `rpl_semi_sync_master_wait_point`(MySQL 5.7+)
        • AFTER_SYNC vs AFTER_COMMIT
    • 五、监控
    • 六、半同步的代价
      • 6.1 增加主库写延迟
      • 6.2 从库故障会影响主库
      • 6.3 网络抖动敏感
    • 七、8.0 的改进
      • 7.1 参数重命名
      • 7.2 性能改进
    • 八、什么时候用
    • 九、和 MGR 的关系
    • 十、和 GTID 配合
    • 十一、故障处理
      • 11.1 半同步一直降级
      • 11.2 主库写入变慢
    • 十二、配置模板
    • 小结

半同步复制:数据安全和服务可用之间怎么权衡

异步复制丢数据,全同步太慢。
半同步是折中方案——但有它自己的坑。

一、三种复制方式对比

方式主库提交时数据安全性性能
异步(默认)写完本地 binlog 就返回主库挂了丢数据最好
半同步等至少一个从库确认收到好中等
全同步等所有从库都应用完最好最差

异步复制丢失数据的场景

1. 主库执行完事务,写 binlog 2. 主库返回"成功"给客户端 3. binlog 还没传给从库 4. 主库宕机 5. 切主 → 这个事务丢了

已经返回成功了,数据却没了——这是最难受的情况。

二、半同步的原理

1. 主库执行事务,写 binlog 2. 主库把 binlog 发给从库 3. 从库收到并写入 relay log,给主库一个 ACK 4. 主库收到 ACK,才返回成功给客户端

注意 ACK 的时机:从库收到 binlog 并落 relay log 就 ACK,
不需要应用完。

所以从库可能"收到了但还没执行"——
中间还有一小段风险窗口,但比异步小得多。

三、怎么配置

3.1 安装插件

主库:

INSTALL PLUGIN rpl_semi_sync_masterSONAME'semisync_master.so';

从库:

INSTALL PLUGIN rpl_semi_sync_slaveSONAME'semisync_slave.so';

8.0 的参数名改了(更中性):

INSTALL PLUGIN rpl_semi_sync_sourceSONAME'semisync_source.so';-- 主INSTALL PLUGIN rpl_semi_sync_replicaSONAME'semisync_replica.so';-- 从

老的参数名在 8.0 还能用(会废弃警告)。

3.2 开启

-- 主库SETGLOBALrpl_semi_sync_master_enabled=ON;SETGLOBALrpl_semi_sync_master_timeout=1000;-- 毫秒-- 从库SETGLOBALrpl_semi_sync_slave_enabled=ON;

从库要重启 IO 线程才生效:

STOP SLAVE IO_THREAD;STARTSLAVE IO_THREAD;

3.3 配置文件(永久)

# 主库 rpl_semi_sync_master_enabled = ON rpl_semi_sync_master_timeout = 1000 rpl_semi_sync_master_wait_for_slave_count = 1 # 从库 rpl_semi_sync_slave_enabled = ON

四、关键参数

4.1rpl_semi_sync_master_timeout

最重要的参数。

SETGLOBALrpl_semi_sync_master_timeout=1000;-- 1 秒

意思是:等从库 ACK 最多等 1 秒,
超时了就降级为异步复制,正常返回给客户端。

这是"半"同步的关键——
它不会无限等待,保证可用性优先。

SHOWSTATUSLIKE'Rpl_semi_sync_master_status';-- ON = 半同步生效中-- OFF = 已降级为异步

4.2rpl_semi_sync_master_wait_no_slave

SETGLOBALrpl_semi_sync_master_wait_no_slave=ON;-- 默认

没有从库连接时怎么办:

值行为
ON(默认)没有从库时继续等待,直到超时降级
OFF没有从库时立刻降级为异步

一般保持默认。

4.3rpl_semi_sync_master_wait_point(MySQL 5.7+)

控制 ACK 的时机:

SETGLOBALrpl_semi_sync_master_wait_point=AFTER_SYNC;-- 默认,推荐
值时机特点
AFTER_SYNC写完 binlog 后、提交前等待无损,推荐
AFTER_COMMIT提交后等待有"幻读"问题
AFTER_SYNC vs AFTER_COMMIT

AFTER_COMMIT 的问题:

1. 主库提交事务(引擎层已提交) 2. 等待从库 ACK 3. 此时其他连接已经能看到这个事务的结果 4. 主库宕机,从库没收到 → 切主后数据没了 5. 但之前读到这个数据的应用以为成功了

这叫"phantom read in failover"。

AFTER_SYNC 的做法:

1. 主库写 binlog 2. 等从库 ACK 3. 收到 ACK 后才提交到引擎层 4. 返回成功

引擎层提交之前就保证了从库已收到,
切换后不会丢。

MySQL 5.7 起默认 AFTER_SYNC,这是无损半同步。

五、监控

SHOWSTATUSLIKE'Rpl_semi_sync%';

主库关键指标:

指标含义
Rpl_semi_sync_master_statusON/OFF,是否降级
Rpl_semi_sync_master_clients有几个半同步从库
Rpl_semi_sync_master_tx_avg_wait_time平均等待 ACK 时间
Rpl_semi_sync_master_no_tx退化为异步的事务数← 重点
Rpl_semi_sync_master_yes_tx半同步成功的事务数
Rpl_semi_sync_master_timeouts超时次数

告警项:

  • Rpl_semi_sync_master_status = OFF→ 已降级
  • Rpl_semi_sync_master_timeouts增长 → 网络或从库有问题

六、半同步的代价

6.1 增加主库写延迟

每个事务多一个网络往返。

网络额外延迟
同机房0.2~1 ms
同城跨机房1~3 ms
跨城10~30 ms

同机房基本无感,跨城就有影响了。

6.2 从库故障会影响主库

从库挂了 → 收不到 ACK → 每个事务都要等 timeout(比如 1 秒)
→主库写性能暴跌。

这是半同步最大的风险点。

缓解:

  1. timeout 设小一点(比如 500ms~1s)
  2. 监控Rpl_semi_sync_master_status,降级时立刻告警
  3. 至少配 2 个半同步从库

6.3 网络抖动敏感

网络一抖,主库写入就卡。

生产建议:主库和至少一个半同步从库放在同机房,
跨机房的从库用异步。

七、8.0 的改进

7.1 参数重命名

rpl_semi_sync_master_* → rpl_semi_sync_source_* rpl_semi_sync_slave_* → rpl_semi_sync_replica_* SHOW SLAVE STATUS → SHOW REPLICA STATUS

老名字还能用(有 deprecation 警告)。

7.2 性能改进

8.0 对半同步的等待机制做了优化,
高并发下性能比 5.7 好不少。

5.7 有个著名的 bug:
半同步在高并发下因为互斥锁导致性能下降严重。8.0 修复了。

八、什么时候用

场景建议
金融、支付、订单用半同步
一般业务,能容忍秒级数据丢失异步就够
跨地域容灾同机房半同步 + 异地异步
从库只是做报表/备份异步(别让它拖慢主库)

典型架构:

主库(机房 A) ├─ 半同步 ─→ 从库 1(机房 A) ← 高可用切换目标 ├─ 异步 ─→ 从库 2(机房 B) ← 异地容灾 └─ 异步 ─→ 从库 3(机房 B) ← 报表查询

只让高可用切换的目标用半同步,别的所有从库都用异步。

九、和 MGR 的关系

MySQL Group Replication(MGR)内部用的就是类半同步机制,
但它是一套完整的组复制方案:

维度半同步复制MGR
故障切换要外部工具(MHA/Orchestrator)内置自动切换
一致性协议简单的 ACKPaxos 变体
写冲突检测无有
多主不支持支持(但少用)
部署复杂度低中

如果只需要"主库写不丢",半同步够用且简单。
如果要自动故障切换,考虑 MGR。

十、和 GTID 配合

gtid_mode = ON enforce_gtid_consistency = ON

有了 GTID,故障切换时能准确判断哪个从库的数据最新。

SELECT@@gtid_executed;-- 对比各实例的 GTID 集合

强烈建议开启 GTID,它让切换变得可靠得多。

十一、故障处理

11.1 半同步一直降级

SHOWSTATUSLIKE'Rpl_semi_sync_master_status';-- OFF

排查:

-- 1. 有几个从库连着SHOWSTATUSLIKE'Rpl_semi_sync_master_clients';-- 2. 从库的 IO 线程状态SHOWSLAVESTATUS\G-- Slave_IO_Running: Yes?-- 3. 从库有没有开半同步SELECT@@rpl_semi_sync_slave_enabled;-- 4. 网络延迟ping/mtr 检查

11.2 主库写入变慢

SHOWSTATUSLIKE'Rpl_semi_sync_master_tx_avg_wait_time';-- 这个值很大说明从库响应慢

可能原因:

  • 从库磁盘 IO 打满(写 relay log 慢)
  • 网络延迟大
  • 从库负载高

应急:先降级为异步恢复主库性能。

SETGLOBALrpl_semi_sync_master_enabled=OFF;

十二、配置模板

# ===== 主库 ===== [mysqld] server_id = 1 log_bin = mysql-bin gtid_mode = ON enforce_gtid_consistency = ON plugin_load = "rpl_semi_sync_master=semisync_master.so" rpl_semi_sync_master_enabled = ON rpl_semi_sync_master_timeout = 1000 rpl_semi_sync_master_wait_point = AFTER_SYNC rpl_semi_sync_master_wait_for_slave_count = 1 # ===== 从库(半同步的那一个)===== [mysqld] server_id = 2 relay_log = relay-bin read_only = ON plugin_load = "rpl_semi_sync_slave=semisync_slave.so" rpl_semi_sync_slave_enabled = ON

小结

维度说明
解决什么异步复制主库宕机丢数据
ACK 时机从库收到 binlog 并落 relay log
关键参数rpl_semi_sync_master_timeout
等待点用 AFTER_SYNC(无损),不用 AFTER_COMMIT
代价每个事务多一个网络往返
最大风险从库故障时主库写入卡顿
监控重点Rpl_semi_sync_master_status、_timeouts

三条实用建议:

  1. 只对高可用切换的目标从库开半同步,其他从库用异步
  2. 半同步从库和主库放同机房,避免跨机房抖动影响主库写入
  3. wait_point用 AFTER_SYNC(MySQL 5.7+ 默认就是这个),
    别手动改成 AFTER_COMMIT

什么时候不用:

  • 数据丢了能重放(比如可以从消息队列重建)
  • 从库经常故障/网络不稳
  • 对写入延迟极度敏感且数据能容忍丢失

半同步是个"用一点性能换数据安全"的取舍,
在支付、订单这类场景很值得;
在日志、埋点这类场景没必要。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询