外观
MySQL 主从复制
如果需要使用 MySQL 服务器提供读写分离支持,则需要 MySQL 的一主多从架构。在一主多从的数据库体系中,多个从服务器采用异步的方式将主数据库的变化同步到从服务器,业务服务器执行写操作或者相关修改数据库的操作直接在主服务器上执行,读操作在各从服务器上执行。MySQL主从复制实现原理如下图所示。

上图所示是典型的 MySQL 一主二从的架构图,其中主要涉及 3 个线程:binlog 线程、I/O 线程和 SQL 线程。每个线程说明如下:
binlog线程:负责将主服务器上的数据更改写入二进制日志中。I/O线程:负责从主服务器上读取二进制日志,并写入从服务器的中继日志中。SQL线程:负责读取中继日志并重放其中的SQL语句。
MySQL 服务之间数据复制的基础是二进制日志文件。一个 MySQL 数据库一旦启用二进制日志后,其作为主服务器,它的数据库中所有操作都会以“事件”的方式记录在二进制日志中,其他数据库作为从服务器,通过一个 I/O 线程与主服务器保持通信,并监控主服务器的二进制日志文件的变化。如果发现主服务器的二进制日志文件发生变化,则会把变化复制到自己的中继日志中,然后从服务器的一个 SQL 线程把相关的“事件”触发操作在自己的数据库中执行,以此实现从数据库和主数据库的一致性,也就实现了主从复制。
二进制日志文件
多个从库会同时读取主库的 binlog 文件吗?会冲突吗?
- 多个从库会同时读取主库的 binlog 文件;
- 多从同时读 binlog 完全不会冲突、互不干扰,MySQL 原生设计就支持多从并行拉取日志。
主库 binlog 读取底层原理
- 主库的二进制日志是顺序追加写入的文件(
binlog.000001、binlog.000002...),只追加、不修改原有内容。 - 每个从库和主库之间建立独立的复制线程(
Binlog Dump线程):- 主库为每一个连接上来的从库,单独创建一条
Dump线程; - 多个从库 = 主库上多条互相独立的
Dump线程。
- 主库为每一个连接上来的从库,单独创建一条
- 每条
Dump线程独立维护自己的读取偏移位置(对应从库保存的master_log_file+read_master_log_pos):- 从库 A 读到
binlog.000100,pos=2000; - 从库 B 读到
binlog.000099,pos=800; - 两者读取位置完全独立,互不影响。
- 从库 A 读到
为什么多从同时读取不会冲突?
- 写入与读取分离
- 主库写
binlog是追加写;从库只是只读读取日志文件,不会修改、截断、覆盖binlog,读操作不会干扰写操作。
- 主库写
- 各从库读取状态完全隔离
- 每个
Dump线程有独立文件句柄、独立文件偏移指针。一个从库读取慢、断连重连,只会重置自己的读取位置,完全不影响其他从库。
- 每个
- 文件系统层面支持多进程并发读
- 操作系统支持多个进程 / 线程同时以只读模式打开同一个文件,无锁竞争、无
IO冲突。
- 操作系统支持多个进程 / 线程同时以只读模式打开同一个文件,无锁竞争、无
binlog 日志被主库清理(expire_logs_days),会对从库造成影响吗?
如果某个从库同步严重滞后,主库自动删除了该从库还没消费完的旧 binlog,该从库会直接同步报错;但其他同步正常的从库不受任何影响。
解决方案:合理设置 binlog 过期时间,或开启从库日志备份。
多从库并发拉取 binlog,会大幅增加主库 IO 压力吗?
会有少量额外 IO 开销,但是可控。
binlog 文件会被操作系统缓存到 PageCache,多个从库读取时,大部分读请求命中内存缓存,不会频繁访问磁盘。从库数量几十台以内,普通主库硬件完全承载。