数据库主从复制:Binlog 与读写分离
数据库主从复制: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 如何驱动复制
主从复制的整体流程分为三个线程协同工作:
- 主库 Binlog Dump 线程:当从库连接主库时,主库会为每个从库创建一个 dump 线程,负责读取主库上的 Binlog 并将增量内容发送给从库。
- 从库 I/O 线程:从库执行
START REPLICA后启动一个 I/O 线程,与主库建立连接,请求指定位置之后的 Binlog。它接收 Binlog 事件并将其写入本地的中继日志(Relay Log)。 - 从库 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 |
确保两台服务器时间同步,可以使用 ntpdate 或 chrony 校准时钟。
主库配置
编辑 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_Running 和 Replica_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_Running、Replica_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 格式确保了数据的一致性;而读写分离则是在此基础上对系统吞吐量的优雅提升。实施过程中,理解原理、做好监控、规避复制延迟陷阱,就能让这套架构平稳运行,为业务的快速发展提供坚实的数据服务底座。