4、主从复制原理:MySQL Binlog解析、异步复制与半同步复制、复制延迟问题

各位同学,今天我们来聊聊MySQL主从复制。说实话,这是我在生产环境中打交道最多的模块之一。很多刚入行的朋友觉得复制很简单——不就是主库写,从库同步嘛。但真到了线上,你会发现坑多得很。

我见过不少团队,因为复制延迟导致数据不一致,最后不得不全量重建从库。也见过因为Binlog格式选错,导致数据恢复时发现少了一截。嗯,今天我们就把这些东西掰开揉碎了讲清楚。

4.1 Binlog:复制的基石

Binlog,全称Binary Log,二进制日志。说白了,它就是MySQL记录所有数据变更的“账本”。主从复制能跑起来,全靠这个日志。

我个人习惯把Binlog理解成“数据库的录像带”。你做的每一次INSERT、UPDATE、DELETE,甚至表结构变更,都会被录下来。从库拿到这盘“录像带”,从头到尾播放一遍,数据就同步了。

Binlog有三种格式,我列个表给你看:

格式 说明 我踩过的坑
STATEMENT 记录SQL语句本身 曾经因为UUID()函数导致主从数据不一致
ROW 记录每一行数据的变化 日志量巨大,但最安全
MIXED 混合模式,MySQL自动选择 某些场景下会退化成STATEMENT

我在项目中遇到过一个问题:主库执行了DELETE FROM t WHERE id > 100 LIMIT 1,STATEMENT格式下,从库可能删掉的是另一条记录。为什么?因为LIMIT 1没有ORDER BY,主从库的数据分布可能不同。从那以后,我所有生产环境都强制使用ROW格式。

核心建议:生产环境请使用ROW格式。虽然日志量大,但数据一致性有保障。磁盘便宜,数据丢了可就贵了。

4.2 异步复制:默认但不够可靠

MySQL默认的复制模式就是异步复制。流程很简单:

  1. 主库提交事务,写入Binlog
  2. 主库直接返回客户端“成功”
  3. 从库通过IO线程拉取Binlog
  4. 从库通过SQL线程回放日志

你想想看,这里有个问题:主库返回成功的时候,从库可能还没拿到数据。如果这时候主库宕机了,数据就丢了。我见过一个案例,某电商平台凌晨做活动,主库突然挂了,丢了大概3秒的数据,结果订单对不上,财务加班对账对了一整天。

异步复制的优点很明显——性能好。主库不用等从库确认,写操作延迟很低。但缺点也很致命——数据可能丢。说白了,这就是用可靠性换性能。

我的经验:如果业务允许丢少量数据(比如日志、统计信息),异步复制完全够用。但如果是金融、订单类业务,千万别这么干。

4.3 半同步复制:折中的方案

半同步复制(Semi-Synchronous Replication)就是为了解决异步复制丢数据的问题而生的。它的核心逻辑是:主库提交事务后,必须等待至少一个从库确认收到了Binlog,才返回客户端成功。

流程变成了这样:

  1. 主库提交事务,写入Binlog
  2. 主库等待从库确认(默认超时10秒)
  3. 从库收到Binlog,写入Relay Log,返回ACK
  4. 主库收到ACK,返回客户端成功

这里有个细节要注意:半同步复制不是“同步复制”。从库只是确认收到了Binlog,并不保证已经回放完成。所以从库仍然可能有延迟,但至少数据不会丢。

我曾经在一个支付系统里配置了半同步复制。配置命令很简单:

-- 主库安装插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

-- 从库安装插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

-- 主库开启
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 10000; -- 超时10秒

-- 从库开启
SET GLOBAL rpl_semi_sync_slave_enabled = 1;

注意:半同步复制有超时机制。如果从库10秒内没确认,MySQL会自动降级为异步复制。我曾经遇到过网络抖动导致频繁降级,后来把超时时间调到了30秒才稳定下来。

4.4 复制延迟:绕不开的痛

复制延迟,说白了就是从库比主库“慢半拍”。我见过最夸张的延迟是几个小时——一个数据分析团队在从库上跑了个大查询,直接把从库的SQL线程卡死了。

延迟的原因有很多,我列几个常见的:

  • 主库写入压力大:主库每秒几万条写入,从库来不及回放
  • 从库配置低:CPU、磁盘IO跟不上主库
  • 大事务:一个事务改了1000万行,从库要慢慢回放
  • 从库上有查询:慢查询会阻塞SQL线程
  • 网络延迟:主从库跨机房,带宽不够

怎么监控延迟?最常用的命令是SHOW SLAVE STATUS\G,重点关注两个字段:

Seconds_Behind_Master: 0  -- 延迟秒数
Master_Log_File: mysql-bin.000123
Read_Master_Log_Pos: 456789
Relay_Master_Log_File: mysql-bin.000123
Exec_Master_Log_Pos: 456789

如果Seconds_Behind_Master一直大于0,说明有延迟。但要注意,这个值不一定准确——如果主从库的时钟不同步,这个值就是错的。我习惯同时对比Master_Log_FileRelay_Master_Log_File,看从库追到了哪个位置。

避坑指南:我曾经遇到一个案例,Seconds_Behind_Master显示为0,但数据就是不一致。后来发现是因为从库的SQL线程卡住了,但IO线程还在正常拉取Binlog。所以只看延迟秒数是不够的,要结合Slave_SQL_Running_State一起看。

4.5 知识体系总览

下面这张图是我自己画的,把主从复制的核心逻辑串起来了。你看一眼,应该能对整个流程有个直观的理解。

主库(Master) 客户端 Binlog InnoDB 从库(Slave) IO线程 Relay Log SQL线程 InnoDB 网络传输 复制延迟 半同步ACK 异步复制:主库不等待ACK,直接返回成功 半同步复制:主库等待ACK,超时后降级为异步 复制延迟常见原因 主库写入压力大 从库配置低 大事务 从库慢查询 网络延迟 主从时钟不同步

这张图把主从复制的核心流程都画出来了。你看,主库的Binlog通过网络传到从库的IO线程,IO线程写入Relay Log,然后SQL线程从Relay Log里读出来回放到从库的InnoDB里。半同步复制就是在主库和从库之间多了一条ACK确认线。

好了,关于主从复制的原理,我们就聊到这里。Binlog格式选ROW,半同步复制保数据,延迟监控要全面——这三句话记住了,线上能少踩很多坑。


公众号:蓝海资料掘金营,微信deep3321