数据库主从复制:Binlog 与读写分离

FreeGuideOnline 最新 2026-06-30

数据库主从复制:Binlog 与读写分离完全指南

本教程将带你从零开始理解数据库主从复制的核心原理,掌握如何通过 Binlog 实现数据同步,并落地读写分离架构以提升系统性能。无论你是后端开发者还是运维新手,都能通过本文构建起可靠的数据库复制体系。

什么是数据库主从复制

主从复制是一种将一台数据库服务器(主库)的数据实时或准实时地复制到一台或多台其他服务器(从库)的技术。它主要用于:

  • 数据热备份:避免单点故障导致数据丢失。
  • 读写分离:主库处理写入,从库分担读取压力。
  • 高可用基础:在主库故障时快速将从库提升为主库。
  • 分析查询卸载:报表和复杂查询可以在从库执行,不影响主库性能。

最常见的实现方式是 MySQL 主从复制,本文将以 MySQL 8.0 为例进行讲解。

Binlog:复制的核心引擎

Binlog 是什么

Binlog(Binary Log)是 MySQL Server 层记录的逻辑日志,它保存了所有可能引起数据变更的 SQL 语句或行数据变化。与 InnoDB 的 redo log(物理日志)不同,Binlog 是面向复制和恢复的通用日志。

Binlog 有三种记录格式,直接影响复制的行为和表现:

  • STATEMENT 模式:记录执行的 SQL 语句本身。节省空间,但某些包含 NOW()UUID() 的函数可能造成主从不一致。
  • ROW 模式:记录每一行数据被修改的具体值。数据一致性最高,但日志量大。
  • MIXED 模式:默认语句模式,当语句可能导致不一致时自动切换为行模式。兼顾性能与一致性。

生产环境中强烈推荐使用 ROW 模式,它是构建可靠复制的基础。

Binlog 如何驱动复制

主从复制的整体流程分为三个线程协同工作:

  1. 主库 Binlog Dump 线程:当从库连接主库时,主库会为每个从库创建一个 dump 线程,负责读取主库上的 Binlog 并将增量内容发送给从库。
  2. 从库 I/O 线程:从库执行 START REPLICA 后启动一个 I/O 线程,与主库建立连接,请求指定位置之后的 Binlog。它接收 Binlog 事件并将其写入本地的中继日志(Relay Log)。
  3. 从库 SQL 线程:从库启动一个 SQL 线程,读取中继日志中的事件,并在本地重放执行,从而完成数据同步。

这三个线程分工明确,保证了数据能有序地从主库流向从库。你可以通过 SHOW REPLICA STATUS 查看它们的运行状态。

搭建主从复制:从零到同步

环境准备

假设你有两台服务器,操作系统为 CentOS 7 或 Ubuntu 20.04,均已安装 MySQL 8.0:

角色 IP 地址 说明
主库 192.168.10.101 server-id = 1
从库 192.168.10.102 server-id = 2

确保两台服务器时间同步,可以使用 ntpdatechrony 校准时钟。

主库配置

编辑 MySQL 配置文件 /etc/my.cnf/etc/mysql/mysql.conf.d/mysqld.cnf

[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
binlog_row_image = full

重启 MySQL 后,使用命令行创建一个专门用于复制的用户:

CREATE USER 'repl'@'192.168.10.102' IDENTIFIED BY 'Repl@Pass123';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.102';
FLUSH PRIVILEGES;

记录当前 Binlog 的位置信息,从库搭建时需要用到:

SHOW MASTER STATUS;

输出会显示当前 Binlog 文件(如 mysql-bin.000001)和 Position(如 157)。此时请锁定主库写入以保证数据一致:

FLUSH TABLES WITH READ LOCK;

如果主库已有业务数据,务必使用 mysqldump 将数据导出并导入到从库后再解锁:

UNLOCK TABLES;

从库配置

修改从库配置文件:

[mysqld]
server-id = 2
relay_log = /var/log/mysql/mysql-relay-bin
read_only = ON
log_bin = /var/log/mysql/mysql-bin      # 从库也可以开启 Binlog,用于级联复制或故障切换
binlog_format = ROW

重启从库 MySQL。如果从主库导入了初始化数据,先恢复数据。然后执行复制配置:

CHANGE REPLICATION SOURCE TO
    SOURCE_HOST = '192.168.10.101',
    SOURCE_USER = 'repl',
    SOURCE_PASSWORD = 'Repl@Pass123',
    SOURCE_LOG_FILE = 'mysql-bin.000001',
    SOURCE_LOG_POS = 157;

启动复制线程并检查状态:

START REPLICA;
SHOW REPLICA STATUS\G

重点观察 Replica_IO_RunningReplica_SQL_Running 是否为 Yes,以及 Seconds_Behind_Source 延迟是否在可接受范围内。若为 0 则表示无延迟。

读写分离:架构与实施策略

为什么要读写分离

在单体数据库架构下,所有读写压力都集中在一台机器上,当读请求量激增时,很容易达到性能瓶颈。通过主从复制将数据分发到多个只读副本后,便可以将读操作路由到从库,让主库专注于事务写入,从而实现:

  • 线性扩展读能力(增加更多从库)
  • 降低主库锁竞争,提升写入性能
  • 服务质量隔离,避免慢查询影响写入

常见的读写分离方案

1. 应用层实现(代码内路由)

在应用的数据访问层封装一个数据源路由器,根据 SQL 类型动态切换数据源:写操作走主库,读操作从从库列表中选择一个。常见工具有 Spring AbstractRoutingDataSource、ShardingSphere-JDBC 等。

优点:轻量、无额外组件、低延迟。 缺点:与语言绑定,需要自行处理负载均衡和故障转移。

2. 中间件代理层

在主库与从库之前架设一个透明代理,由中间件对 SQL 进行解析和路由。流行的开源项目包括:

  • ProxySQL:高性能 MySQL 代理,支持查询规则、读写分离、连接池管理等。
  • MaxScale:MariaDB 维护的数据库中间件,支持多种路由策略。
  • MySQL Router:InnoDB Cluster 的官方路由组件,适合与 MySQL 组复制搭配。

代理层方案对应用完全透明,语言无关,但会增加一层网络延迟,并需要维护中间件高可用。

3. 数据库驱动层实现

部分数据库驱动(如 MySQL Connector/J)支持多个后端地址的配置,并允许基于事务状态或只读提示做路由。例如 JDBC 的 ReplicationDriver

jdbc:mysql:replication://master-host:3306,slave1:3306/database

应用将连接设置为只读时,驱动自动路由到从库。实现简单,但灵活性有限。

读写分离不得不面对的挑战

复制延迟是读写分离最棘手的问题。从库数据不可能与主库实时完全一致,可能造成“刚写入却读不到”的现象。解决方案包括:

  • 强制读主库:在写入后的一定时间内(或同一个事务上下文中)将特定读请求发往主库。
  • 延迟阈值监控:监控 Seconds_Behind_Source,若超过阈值,临时暂停从库的读流量。
  • 半同步复制:开启 semi-sync 插件,确保至少一个从库收到 Binlog 后才返回客户端,显著降低延迟风险。
  • 最终一致性容错:在业务层面允许短暂不一致,如缓存失效后第一次读取可能得到旧数据,但很快会被刷新。

常见故障排查与维护

复制中断的常见原因

  • 主库删除了一条从库尚在使用的记录:从库 SQL 线程报错 Could not execute Delete_rows event。解决方法:手动跳过错误 SET GLOBAL SQL_REPLICA_SKIP_COUNTER = 1,但需谨慎评估数据一致性。
  • 从库写入了数据导致冲突:务必保证从库 read_only 开启,且复制用户不能跳过 read_only 检查。
  • 网络闪断:I/O 线程自动重连,无需干预;若长时间断开,主库 Binlog 被清理,则需要重新构建从库。

日常监控指标

  • 复制状态:确保 Replica_IO_RunningReplica_SQL_Running 均为 Yes。
  • 主从延迟SHOW REPLICA STATUS 中的 Seconds_Behind_Source,设置合理告警阈值。
  • Binlog 磁盘占用:定期检查并清理过期的 Binlog,配合 binlog_expire_logs_seconds 参数(MySQL 8.0 以上)自动删除。
  • 主库写负载:避免大事务,它会瞬间产生巨大 Binlog 事件,可能阻塞从库 SQL 线程。

无损切换与高可用

单靠主从复制并不能实现自动故障切换,通常需要结合高可用方案:

  • MHA (Master High Availability):监控主库,故障时自动将从库提升,并尽量补齐日志。
  • Orchestrator:管理复杂的复制拓扑,智能恢复和切换。
  • MySQL InnoDB Cluster:基于 Group Replication 的内生高可用方案,无需中间件。

对于初级架构,可手动执行切换:停止写流量,将所有从库追平主库,然后选择一台提升为主库,其他从库重新指向新主库。

总结

数据库主从复制是构建高性能、高可用系统的基石。Binlog 作为复制的核心媒介,其 ROW 格式确保了数据的一致性;而读写分离则是在此基础上对系统吞吐量的优雅提升。实施过程中,理解原理、做好监控、规避复制延迟陷阱,就能让这套架构平稳运行,为业务的快速发展提供坚实的数据服务底座。