
1. 什么是 MySQL 主从复制
MySQL 主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。
对于多级复制,数据库服务器即可充当主机,也可充当从机。MySQL 主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新。
MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
2. MySQL 主从复制实现的原理
MySQL 主从复制涉及到三个线程,一个运行在主节点(log dump thread
),其余两个 (I/O thread
, SQL thread
) 运行在从节点,如下图所示:

主节点 binary log dump
线程
当从节点连接主节点时,主节点会创建一个 log dump
线程,用于发送 bin-log
的内容。在读取 bin-log
中的操作时,此线程会对主节点上的bin-log
加锁,当读取完成,甚至在发动给从节点之前,锁会被释放。
从节点 I/O
线程
当从节点上执行 start slave
命令之后,从节点会创建一个 I/O
线程用来连接主节点,请求主库中更新的 bin-log
。I/O
线程接收到主节点 binlog dump
进程发来的更新之后,保存在本地 relay-log
中。
从节点 SQL
线程
SQL 线程负责读取 relay log
中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。
对于每一个主从连接,都需要三个进程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个 binary log dump
进程,而每个从节点都有自己的 I/O
进程,SQL
进程。从节点用两个线程将从主库拉取更新和执行分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。比如,如果从节点没有运行,此时 I/O
进程可以很快从主节点获取更新,尽管 SQL
进程还没有执行。如果在 SQL
进程执行之前从节点服务停止,至少 I/O
进程已经从主节点拉取到了最新的变更并且保存在本地 relay
日志中,当服务再次起来之后,就可以完成数据的同步。
要实施复制,首先必须打开 Master
端的 binary log(bin-log)
功能,否则无法实现。因为整个复制过程实际上就是 Slave
从 Master
端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。如下图所示:

复制的基本过程如下:
-
从节点上的 I/O
线程连接主节点,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
-
主节点接收到来自从节点的 I/O
请求后,通过负责复制的 I/O
进程根据请求信息读取指定日志指定位置之后的日志信息,返回给从节点。返回信息中除了日志所包含的信息之外,还包括本次返回的信息的 bin-log file
的以及 bin-log position
;从节点的 I/O
线程接收到内容后,将接收到的日志内容更新到本机的 relay log
中,并将读取到的 binary log
文件名和位置保存到 master-info
文件中,以便在下一次读取的时候能够清楚的告诉 Master
“我需要从某个 bin-log
的哪个位置开始往后的日志内容,请发给我”;
-
Slave
的 SQL
线程 检测到 relay-log
中新增加了内容后,会将 relay-log
的内容解析成在主节点上实际执行过的操作,并在本数据库中执行。
3. MySQL 主从复制的用途(解决的问题)
4. MySQL 主从复制的类型
binlog
有三种格式:Statement
、Row
以及 Mixed
。
基于语句的复制(statement-based replication,SBR):
主服务器上面执行的语句在从服务器上面再执行一遍。
优点:
是只需要记录会修改数据的 sql
语句到 binlog
中,减少了 binlog
日志量,节约 I/O
,提高性能。
缺点:
是在某些情况下,会导致主从节点中数据不一致(比如 sleep()
, now()
等), 时间上可能不完全同步造成偏差,执行语句的用户也可能是不同一个用户。
基于行的复制(row-based replication,RBR):
将 SQL 语句分解为基于 Row
更改的语句并记录在 bin log
中,也就是只记录哪条数据被修改了,修改成什么样。
优点:
是不会出现某些特定情况下的存储过程、或者函数、或者 trigger
的调用或者触发无法被正确复制的问题。
缺点:
是会产生大量的日志,尤其是修改 table
的时候会让日志暴增, 同时增加 bin log
同步时间。也不能通过 bin log
解析获取执行过的 sql
语句,只能看到发生的 data
变更。
混合类型的复制(mixed-based replication,MBR):
MySQL 默认使用基于语句的复制,当基于语句的复制会引发问题的时候就会使用基于行的复制,MySQL 会自动进行选择。
在 MySQL 主从复制架构中,::读操作可以在所有的服务器上面进行,而写操作只能在主服务器上面进行::。主从复制架构虽然给读操作提供了扩展,可如果写操作也比较多的话(多台从服务器还要从主服务器上面同步数据),单主模型的复制中主服务器势必会成为性能瓶颈。
5. MySQL 主从复制模式
MySQL 主从复制默认是异步的模式。MySQL 增删改操作会全部记录在 binary log
中,当 slave
节点连接 master
时,会主动从 master
处获取最新的 bin log
文件。并把 bin log
中的 sql relay
。
异步模式(mysql async-mode)
这种模式下,主节点不会主动 `push bin log` 到从节点,这样有可能导致 `failover` 的情况下,也许从节点没有即时地将最新的 `bin log` 同步到本地

半同步模式(mysql semi-sync)
这种模式下主节点只需要接收到其中一台从节点的返回信息,就会 `commit`;否则需要等待直到超时时间然后切换成异步模式再提交;这样做的目的可以使主从数据库的数据延迟缩小,可以提高数据安全性,确保了事务提交后,`binlog` 至少传输到了一个从节点上,不能保证从节点将此事务更新到`db` 中。性能上会有一定的降低,响应时间会变长。

半同步模式不是 MySQL 内置的,从 mysql 5.5
开始集成,需要 master
和 slave
安装插件开启半同步模式。
全同步模式
全同步模式是指主节点和从节点全部执行了 commit 并确认才会向客户端返回成功。
GTID 复制模式
@ 在传统的复制里面,当发生故障,需要主从切换,需要找到 `binlog` 和 `pos` 点,然后将主节点指向新的主节点,相对来说比较麻烦,也容易出错。在 MySQL 5.6 里面,不用再找 `binlog` 和 `pos` 点,我们只需要知道主节点的 `ip`,端口,以及账号密码就行,因为复制是自动的,MySQL 会通过内部机制 GTID 自动找点同步。
@ 多线程复制(基于库),在 MySQL 5.6 以前的版本,`slave` 的复制是单线程的。一个事件一个事件的读取应用。而 `master` 是并发写入的,所以延时是避免不了的。唯一有效的方法是把多个库放在多台 `slave`,这样又有点浪费服务器。在 MySQL 5.6 里面,我们可以把多个表放在多个库,这样就可以使用多线程复制。
基于 GTID 复制实现的工作原理:
* 主节点更新数据时,会在事务前产生 GTID,一起记录到 `binlog` 日志中。
* 从节点的 I/O 线程将变更的 `binlog`,写入到本地的 `relay log` 中。
* SQL 线程从 `relay log` 中获取 GTID,然后对比本地 `binlog` 是否有记录(所以 MySQL 从节点必须要开启 `binary log`)。
* 如果有记录,说明该 GTID 的事务已经执行,从节点会忽略。
* 如果没有记录,从节点就会从 `relay log` 中执行该 GTID 的事务,并记录到 `binlog`。
* 在解析过程中会判断是否有主键,如果没有就用二级索引,如果有就用全部扫描。
6. MySQL 主从形式
一主一从

一主多从,提高系统的读性能

一主一从和一主多从是最常见的主从架构,实施起来简单并且有效,不仅可以实现 HA
,而且还能读写分离,进而提升集群的并发能力。
多主一从 (从5.7开始支持)

多主一从可以将多个 mysql
数据库备份到一台存储性能比较好的服务器上。
双主复制

双主复制,也就是互做主从复制,每个 master
既是 master
,又是另外一台服务器的 slave
。这样任何一方所做的变更,都会通过复制应用到另外一方的数据库中。
级联复制

级联复制模式下,部分 slave
的数据同步不连接主节点,而是连接从节点。因为如果主节点有太多的从节点,就会损耗一部分性能用于 replication
,那么我们可以让 3~5
个从节点连接主节点,其它从节点作为二级或者三级与从节点连接,这样不仅可以缓解主节点的压力,并且对数据一致性没有负面影响。
7. 如何配置一主一从
- 安装 MySQL, 保证版本一致, MySQL 主服务器 IP ->
192.16.168.18
, MySQL 从服务器 IP -> 192.16.168.19
# server
$ sudo apt-get install mysql-server
# client
$ sudo apt-get install mysql-client
- 配置 MySQL 主服务器
# 主服务器上为服务器设置一个连接账户并授予 REPLICATION SLAVE 权限
$ GRANT REPLICATION SLAVE ON *.* TO '$username'@'%' IDENTIFIED BY '$password';
$username 表示用户名,% 表示所有的电脑都可以连接,还可以这样: `10.11.4.%`, 也可以设置某个 ip 地址运行连接,$password 表示密码
$ GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.11.4.%' IDENTIFIED BY 'repl';
# 执行 flush privileges; 命令立即生效
$ flush privileges;
# 编辑 MySQL 配置文件
$ sudo vim /etc/my.cnf
# 配置信息
server-id=1 # 必须。设置服务器 id,为 1 表示主服务器。规范为服务器 IP 的后段
log_bin=mysql-bin # 必须。启动 mysql 二进制日志系统。
binlog-do-db=osyunweidb # 需要同步的数据库名,如果有多个数据库,可重复此参数,每个数据库一行
binlog-ignore-db=mysql # 不同步 mysql 系统数据库,如果有多个数据库,可重复此参数,每个数据库一行
binlog-ignore-db=information_schema
binlog_format=STATEMENT # 设置 logbin 格式
# 重启 MySQL 服务
$ sudo service mysql restart
# 查看 master 服务状态, 如下图
$ show master status;

- 配置 MySQL 从服务器
# 编辑 MySQL 配置文件
$ sudo vim /etc/my.cnf
# 配置信息
server-id=2 # 必须。设置服务器id,为 2 表示从服务器。规范为服务器 IP 的后段
relay-log=mysql-relay # 启用中继日志
# 停止 slave 同步进程
slave stop;
# 执行同步语句
CHANGE MASTER TO MASTER_HOST='$ip', MASTER_USER='$username', MASTER_PASSWORD='$password', MASTER_LOG_FILE='$master_log_file', MASTER_LOG_POS=$master_log_position;
$ip 表示用 IP 地址, $username 表示用户名,$password 表示密码
CHANGE MASTER TO MASTER_HOST='192.168.0.120', MASTER_USER='repl', MASTER_PASSWORD='repl@20170509', MASTER_LOG_FILE='binlog.000004', MASTER_LOG_POS=154;
# 开启 slave 同步进程
slave start;
# 查看 slave 同步信息。注意:一定要看输出的信息
show slave status;
# 重启 MySQL 服务
$ sudo service mysql restart
# 查看 master、slave 相关进程
$ show processlist;

两个参数都是 Yes,则说明主从配置成功!
# 如何停止从服务复制功能
stop slave;
# 如何重新配置主从
stop slave;
reset master;
8. 如何配置双主双从
双主机配置
Master 1 /etc/my.cnf
配置:
server-id=1 # 主服务器唯一ID
log-bin=mysql-bin # 启用二进制日志
binlog-ignore-db=mysql # 设置不要复制的数据库(可设置多个)
binlog-ignore-db=information_schema
binlog-do-db=需要复制的主数据库名字 # 设置需要复制的数据库
binlog_format=STATEMENT # 设置 logbin 格式
log-slave-updates # 在作为从数据库的时候,有写入操作也要更新二进制日志文件
auto-increment-increment=2 # 表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1,取值范围是1 .. 65535
auto-increment-offset=1 # 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535
Master 2 /etc/my.cnf
配置:
server-id=3 # 主服务器唯一ID
log-bin=mysql-bin # 启用二进制日志
binlog-ignore-db=mysql # 设置不要复制的数据库(可设置多个)
binlog-ignore-db=information_schema
binlog-do-db=需要复制的主数据库名字 # 设置需要复制的数据库
binlog_format=STATEMENT # 设置 logbin 格式
log-slave-updates # 在作为从数据库的时候,有写入操作也要更新二进制日志文件
auto-increment-increment=2 # 表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1,取值范围是1 .. 65535
auto-increment-offset=2 # 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535
双从机配置
Slave 1 /etc/my.cnf
配置:
server-id=2 # 从服务器唯一ID
relay-log=mysql-relay # 启用中继日志
Slave 2 /etc/my.cnf
配置:
server-id=4 # 从服务器唯一ID
relay-log=mysql-relay # 启用中继日志
# 3. 双主机、双从机重启 mysql服务
$ sudo service mysql restart
# 4. 主机从机都关闭防火墙
# 5. 在两台主机上建立帐户并授权 slave
$ GRANT REPLICATION SLAVE ON *.* TO '$username'@'%' IDENTIFIED BY '$password';
$username 表示用户名,% 表示所有的电脑都可以连接,还可以这样: `10.11.4.%`, 也可以设置某个 ip 地址运行连接,$password 表示密码
$ GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.11.4.%' IDENTIFIED BY 'repl';
# 6. 查询 Master 1 的状态, 记录下 File 和 Position 的值, Master 2 同理, 执行完此步骤后不要再操作主服务器 MYSQL,防止主服务器状态值变化
$ show master status;
# 7. 在从机上配置需要复制的主机, Slava 1 复制 Master 1,Slava 2 复制 Master 2, 执行同步语句
$ CHANGE MASTER TO MASTER_HOST='$ip', MASTER_USER='$username', MASTER_PASSWORD='$password', MASTER_LOG_FILE='$master_log_file', MASTER_LOG_POS=$master_log_position;
$ip 表示用 IP 地址, $username 表示用户名,$password 表示密码
# 8. 启动两台从服务器复制功能
$ start slave;
# 9. 查看从服务器状态, `Slave_IO_Running: Yes`, `Slave_SQL_Running: Yes`, 两个参数都是 `Yes`, 表示成功
$ show slave status \G;
# 10. 两个主机互相复制, 之后执行 `start slave; ` 以及 `show slave status \G;`
$ CHANGE MASTER TO MASTER_HOST='$ip', MASTER_USER='$username', MASTER_PASSWORD='$password', MASTER_LOG_FILE='$master_log_file', MASTER_LOG_POS=$master_log_position;
$ip 表示用 IP 地址, $username 表示用户名,$password 表示密码
# 11. 如何停止从服务复制功能
$ stop slave;
# 12. 如何重新配置主从
$ stop slave;
$ reset slave;
9. 测试 MySQL 主从服务器同步
首先主从 MySQL 都要有某个相同的数据库存在!
Step-One:在 MySQL 主服务器创建一张表 demo
Step-Two:在 MySQL 从服务器查询表 demo
要是 MySQL 从服务器存在 demo 表即已经成功!