09. 主从复制与数据同步

数据库主从复制原理:异步/半同步/组复制模式、binlog 格式与 GTID、复制延迟原因与并行复制优化方案。

1. 复制架构

                ┌──────────────┐
                │    Client    │
                └──────┬───────┘
                       │
                 ┌─────▼─────┐
                 │   Master  │  ← 处理写请求,记录 binlog
                 │  (主库)   │
                 └─────┬─────┘
                       │ binlog dump
         ┌─────────────┼─────────────┐
         ↓             ↓             ↓
    ┌────────┐   ┌────────┐   ┌────────┐
    │ Slave 1│   │ Slave 2│   │ Slave 3│  ← 读请求
    │(IO线程) │   │(IO线程) │   │(IO线程) │
    │(SQL线程)│   │(SQL线程)│   │(SQL线程)│
    └────────┘   └────────┘   └────────┘

2. 复制模式

2.1 异步复制(Asynchronous)

Client → Master (写入成功) → 立即返回
              ↓ 后台异步
           Slave(可能有延迟)

特点:快,不阻塞客户端,但 Master 宕机时可能丢失未同步数据
MySQL 默认模式

2.2 半同步复制(Semi-Synchronous)

Client → Master (prepare) → 等待至少 1 个 Slave ACK
                ↓
             Slave (收到 relay log)
                → ACK → Master commit → 返回客户端

特点:返回慢一些,但保证至少一个 Slave 已接收数据,降低丢失风险

2.3 组复制(Group Replication)

多主或单主模式,多数派确认后提交(Paxos 协议)。
自动故障检测和切换,数据强一致。
MySQL 5.7+ 内置。
模式一致性性能故障场景数据丢失
异步最终一致最高可能丢失所有未同步
半同步至少一个副本中最多丢失一个事务
组复制强一致较低不丢失(多数派确认)

3. Binlog

3.1 格式

格式内容优点缺点
STATEMENT原始 SQL 语句体积小非确定性函数(UUID/ NOW())问题
ROW行变更前后镜像精确、安全体积大(UPDATE 全表时膨胀)
MIXED混合策略平衡复杂
-- 推荐配置(ROW 格式)
SET GLOBAL binlog_format = 'ROW';
SET GLOBAL binlog_row_image = 'FULL';  -- FULL / MINIMAL / NOBLOB

-- ROW 格式示例
-- UPDATE users SET status = 'active' WHERE id = 1
-- binlog 记录:
--   before_image: id=1, status='inactive'
--   after_image:  id=1, status='active'

3.2 GTID(全局事务标识)

GTID = Master_UUID:Transaction_Sequence

示例:
  a1b2c3d4-e5f6-7890-abcd-ef1234567890:1-100
  
优势:
  - 自动定位复制位点,避免 file:position 管理
  - 故障切换更简单(CHANGE MASTER TO ... AUTO_POSITION=1)
  - 避免跳过事务导致的脑裂

4. 复制延迟

4.1 延迟原因

原因说明
单线程 SQL 线程经典 MySQL 只有 1 个 SQL 线程重放
大事务一个事务修改大量行,Slave 重放慢
Slave 性能差Slave 硬件弱于 Master
锁竞争Slave 上也有读请求,与 SQL 线程竞争

4.2 并行复制

-- MySQL 5.7+ 并行复制配置
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL slave_parallel_workers = 8;  -- SQL 线程数

-- LOGICAL_CLOCK:基于组提交(同一时刻提交的事务可并行)
-- DATABASE:基于库级别并行(不同库的事务并行)

4.3 监控延迟

-- 查看延迟
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master: 0  ← 延迟秒数

-- 更精确的方法(pt-heartbeat)
-- Master 每秒写 heartbeat 表,Slave 计算差值

5. 复制延迟的根因分析与排查方法论

生产环境中复制延迟是最常见的故障之一。排查时应遵循「三步定位法」:

第一步:确认延迟程度

SHOW SLAVE STATUS\G
-- 关注 Seconds_Behind_Master(估算延迟秒数)
-- Slave_SQL_Running_State(SQL 线程当前状态)

第二步:定位瓶颈环节

  • IO 线程慢:网络带宽不足、sync_binlog=1 导致频繁 fsync
  • SQL 线程慢:单线程重放、大事务、表锁冲突、Slave 硬件性能差

第三步:针对性优化

  • 网络层:专线通信、压缩传输(slave_compressed_protocol=1)
  • 硬件层:Slave 使用 SSD、增加 IO 容量
  • 配置层:启用并行复制、调整 innodb_flush_log_at_trx_commit=2

更精确的延迟测量应使用 pt-heartbeat 工具:Master 每秒更新 heartbeat 表,Slave 计算时间差值,避免 Seconds_Behind_Master 在空闲时显示为 0 的假象。

6. 读写分离的实践方案

方案实现方式优点缺点
ProxySQL中间件代理透明、支持查询路由规则增加一层网络延迟
MySQL Router官方中间件与 MGR 深度集成功能相对简单
应用层拆分代码中区分读写数据源最灵活、零中间件依赖代码侵入性强

7. 故障自动切换架构

方案自动切换数据一致性适用场景
MHA✅可能丢少量数据传统 MySQL 主从
Orchestrator✅可配置大规模拓扑管理
MGR✅ 内置强一致(多数派)MySQL 5.7+ 推荐

8. 复制链与拓扑监控

8.1 多层级联复制架构

                    ┌─────────┐
                    │ Master  │
                    └────┬────┘
                         │ binlog
                    ┌────┴────┐
                    │ Relay   │  ← 级联中继 Slave(log-slave-updates=ON)
                    │ Slave   │
                    └────┬────┘
                         │ binlog
              ┌─────────┼─────────┐
              ↓         ↓         ↓
         ┌────────┐┌────────┐┌────────┐
         │ Read 1 ││ Read 2 ││ Read 3 │
         └────────┘└────────┘└────────┘

级联复制(Cascading Replication)适用于跨地域部署场景:主库仅需向一个中继节点发送 binlog,由中继节点分发给各区域的只读副本,显著降低主库的网络负载。

关键配置:

-- 中继节点必须开启 log-slave-updates,否则不会转发 binlog
SET GLOBAL log_slave_updates = ON;
-- 中继节点同样需要 binlog 格式为 ROW
SET GLOBAL binlog_format = 'ROW';

8.2 复制延迟监控指标体系

指标名获取方式正常范围异常阈值
Seconds_Behind_MasterSHOW SLAVE STATUS0-1s> 5s
Slave_IO_StateSHOW SLAVE STATUS“Waiting for master…”“Connecting to master…”
Master_Log_File / Read_Master_Log_PosSHOW SLAVE STATUS接近主库 binlog 位置差距 > 1GB
Exec_Master_Log_PosSHOW SLAVE STATUS接近 Read_Master_Log_Pos差距 > 100MB
Slave_SQL_Running_StateSHOW SLAVE STATUS显示正常状态“Waiting for dependent transaction…”

更精准的监控应结合 performance_schema:

-- MySQL 8.0 复制性能监控
SELECT 
    WORKER_ID,
    LAST_SEEN_TRANSACTION,
    LAST_ERROR_NUMBER,
    LAST_ERROR_MESSAGE
FROM performance_schema.replication_applier_status_by_worker;

-- 复制延迟精确测量(pt-heartbeat)
SELECT 
    round(MAX(age), 2) AS max_replication_lag_seconds
FROM percona.heartbeat;

8.3 binlog 刷盘策略与数据安全

-- sync_binlog 配置对比
SET GLOBAL sync_binlog = 1;   -- 每次事务都 fsync,最安全,性能最低
SET GLOBAL sync_binlog = 100; -- 每 100 个事务 fsync,平衡方案
SET GLOBAL sync_binlog = 0;   -- 由 OS 决定刷盘,性能最高,宕机可能丢失

-- innodb_flush_log_at_trx_commit 配合
SET GLOBAL innodb_flush_log_at_trx_commit = 1;  -- 最安全:每次事务 Redo Log 刷盘
-- 非核心读库可设为 2(每秒刷盘)以提升 Slave 重放性能

生产建议:

  • 金融级主库:sync_binlog=1 + innodb_flush_log_at_trx_commit=1(双一配置)
  • 一般业务主库:sync_binlog=1 + innodb_flush_log_at_trx_commit=2
  • 只读从库:sync_binlog=0 + innodb_flush_log_at_trx_commit=2(只读库不需要 binlog 持久化)

9. 云原生时代的复制架构演进

AWS Aurora、阿里云 PolarDB 等通过「共享存储 + 日志即数据」架构,将复制简化为只读节点回放 Redo Log:

  • 写节点只管写日志到共享存储
  • 读节点从共享存储读取日志并应用
  • 复制延迟降低到毫秒级,不受事务大小影响

这种架构下,传统的 binlog-based 复制不再是性能瓶颈,开发者可以更专注于业务逻辑而非复制调优。然而,云原生数据库也存在 vendor lock-in 风险,迁移成本需要考虑。


延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「database」更多文章

  1. PostgreSQL 锁与阻塞分析
  2. COPY 与批量数据加载优化
  3. pgvector 向量检索与混合查询