---
title: 半同步复制
description: "半同步复制是指主库在执行完客户端提交的事务后不会立刻把结果返回给客户端，会调用dump线程通知从库有新事务产生，从库调用I/O线程把获取到的主库binlog写入relay log然后返回ACK报文给主库，同时调用SQL线程回放relay log把更新写入本地磁盘，主库调用dump线程接收到一个从库返回的ACK报文后确认事务执行成功，把结果返回客户端。MySQL 5.5开始，MySQL官方提供了半同步复制插件，主库在发生故障后，从库可以拥有完整的数据副本，所以半同步复制解决了异步复制主从数据不一致问题，但同时造成一定程度的时延，会影响业务性能。"
url: https://www.hikunpeng.com/document/detail/zh/kunpengdbs/ecosystemEnable/MySQL/kunpengmysqlmasterslave_03_0006.html
sourcePath: /source/zh/kunpengdbs/ecosystemEnable/MySQL/kunpengmysqlmasterslave_03_0006.html
indexId: 65f7bab87389239e3843d9b35ce1a49dd185740abbce79261b110bf9e018bf8580
---
# 半同步复制

#### 简介

半同步复制是指主库在执行完客户端提交的事务后不会立刻把结果返回给客户端，会调用dump线程通知从库有新事务产生，从库调用I/O线程把获取到的主库binlog写入relay log然后返回ACK报文给主库，同时调用SQL线程回放relay log把更新写入本地磁盘，主库调用dump线程接收到一个从库返回的ACK报文后确认事务执行成功，把结果返回客户端。MySQL 5.5开始，MySQL官方提供了半同步复制插件，主库在发生故障后，从库可以拥有完整的数据副本，所以半同步复制解决了异步复制主从数据不一致问题，但同时造成一定程度的时延，会影响业务性能。


#### 业务流程

1. 客户端调用用户线程向主库发起数据更新请求，主库在执行完更新操作后把变更写入binlog，主库启动dump线程时调用add_slave()函数将所有从库添加到一个监测队列中，向从库发送报文时调用updateSyncHeader()函数更新报文头中的semi-sync标记。
2. 从库调用IO线程获取主库的binlog后，调用slaveReadSyncHeader()函数判断报文头中是否有semi-sync标记。如果报文头中有semi-sync标记，从库把接收到的binlog写入relay log后，调用slaveReplay()函数返回ACK报文给主库。从库调用SQL线程回放relay log，即把更新写入本地磁盘。
3. 主库调用ack_receiver线程监测所有从库，调用handleAck()函数将当前binlog中的位置记录到ack_array数组中，收到一个从库回复（rpl_semi_sync_master_wait_for_slave_count == 1）后调用reportReplyBinlog()函数唤醒工作线程，返回成功给客户端。


图1 MySQL半同步复制

#### 事务提交阶段的处理逻辑

事务提交阶段的处理逻辑分为after_sync（更可靠）和after_commit，推荐使用after_sync模式。


- after_sync是指用户线程在调用binlog sync之后，主库会等待接收来自从库的ACK报文，当接收到一个从库的ACK报文后，主库启用Engine commit执行流程。after_sync模式会触发事务堆积，有利于group commit（组提交），从而提升Engine commit的性能。
  图2 after_sync的逻辑处理流程

- after_commit是指Engine commit操作在接收到从库的ACK报文之前执行，但执行结果并未返回给客户端，当接收到从库的ACK报文之后，再把执行结果返回给客户端。如果在接收到从库的ACK报文之前执行Engine commit，其他客户端会读取到已提交的事务，如果从库还没有读到该事务，同时主库发生崩溃，然后手动切换到从库，那么之前读到的事务已经不存在，即导致数据不一致。
  图3 after_commit的逻辑处理流程


#### 适用场景

半同步复制的优点是数据丢失为零，但其缺点是时延较大，所以半同步复制适用于网络时延高，不接受数据丢失的业务场景。
