You'blog

MySQL主从复制原理

2018-01-02

MySQL支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。MySQL复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器上已经记录到其二进制日志的保存的更新。当一个从服务器连接主服务器时,它通知主服务器定位到从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,并在本机上执行相同的更新。然后封锁并等待主服务器通知新的更新。从服务器执行备份不会干扰主服务器,在备份过程中主服务器可以继续处理更新。

MySQL使用3个线程来执行主从复制功能,其中两个线程(SQL线程和IO线程)在从服务器,另外一个线程(IO线程)在主服务器。当发出START SLAVE时,从服务器创建一个I/O线程,以连接主服务器并让它发送记录在其二进制日志中的语句。主服务器创建一个线程将二进制日志中的内容发送到从服务器。该线程可以即为主服务器上SHOW PROCESSLIST的输出中的Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷贝到从服务器数据目录中的本地文件中,即中继日志。第3个线程是SQL线程,由从服务器创建,用于读取中继日志并执行日志中包含的更新。在从服务器上,读取和执行更新语句被分成两个独立的任务。当从服务器启动时,其I/O线程可以很快地从主服务器索取所有二进制日志内容,即使SQL线程执行更新的远远滞后。

1. Binlog dump thread.

当Slave连接Master的时候,Master创建一个线程来发送二进制文件内容。用 SHOW PROCESSLIST 可以识别出 Binlog Dump 线程。状态如下:

1
Master has sent all binlog to slave; waiting for binlog to be updated

线程已经从二进制日志读取所有主要的更新并已经发送到了从服务器。线程现在正空闲,等待由主服务器上的更新。

2. Slave I/O thread.

当Slave 执行 START SLAVE 语句,SLave创建一个I/O线程,连接到Master,要求Master发送记录在二进制日志的更新。Slave I/O线程读取Master的binlog Dump线程发送的更新,并将其复制到本地文件,即中继日志。这个线程的状态如果用 SHOW SLAVE STATUS 查看显示为:Slave_IO_running,如果用 SHOW STATUS 查看显示为:Slave_running。用 SHOW PROCESSLIST 查看state 如下:

1
Waiting for master to send event

线程已经连接上主服务器,正等待二进制日志事件到达。如果主服务器正空闲,会持续较长的时间。如果等待持续slave_read_timeout秒,则发生超时。此时,线程认为连接被中断并企图重新连接。

3. Slave SQL thread.

Slave创建一个SQL线程读取中继日志,由Slave IO线程写入,并执行其中的事件。用SHOW PROCESSLIST查看state 如下:

1
Slave has read all relay log; waiting for the slave I/O thread to update it

线程已经处理了中继日志文件中的所有事件,现在正等待I/O线程将新事件写入中继日志。

在前面的介绍中,每个主从连接都有3个线程。如果由多个从则主会为每个从创建一个Binlog dump thread,每个从机都有自己的I/O和SQL线程。

在Master Server 执行 SHOW PROCESSLIST 显示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mysql> show processlist\G
*************************** 1. row ***************************
Id: 6
User: wsy
Host: 192.168.4.129:36723
db: NULL
Command: Binlog Dump
Time: 5746
State: Master has sent all binlog to slave; waiting for binlog to be updated
Info: NULL
*************************** 2. row ***************************
Id: 7
User: root
Host: localhost
db: NULL
Command: Query
Time: 0
State: NULL
Info: show processlist
2 rows in set (0.00 sec)
Here, thread 6 is a Binlog Dump replication thread that services a connected slave.

在Slave Server 执行 SHOW PROCESSLIST 显示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
mysql> show processlist\G
*************************** 1. row ***************************
Id: 8
User: root
Host: localhost
db: NULL
Command: Query
Time: 0
State: NULL
Info: show processlist
*************************** 2. row ***************************
Id: 13
User: system user
Host:
db: NULL
Command: Connect
Time: 6279
State: Waiting for master to send event
Info: NULL
*************************** 3. row ***************************
Id: 14
User: system user
Host:
db: NULL
Command: Connect
Time: 6039
State: Slave has read all relay log; waiting for the slave I/O thread to update it
Info: NULL
3 rows in set (0.00 sec)
The State information indicates that thread 13 is the I/O thread that is communicating with the master server, and thread 14 is the SQL thread that is processing the updates stored in the relay logs.

默认情况,中继日志使用host_name-relay-bin.nnnnnn形式的文件名存放在data目录中,其中host_name是从服务器主机名,nnnnnn是序列号。中继日志与二进制日志的格式相同,并且可以用mysqlbinlog读取。

一个Slave Server会创建两个文件在data目录中,这两个文件名默认为 master.inforelay-log.info。用--master-info-file--relay-log-info-file 选项来改变这些文件的名字和位置。状态文件保存在硬盘上,从服务器关闭时不会丢失。下次从服务器启动时,读取这些文件以确定它已经从主服务器读取了多少二进制日志,以及处理自己的中继日志的程度。

如果您要备份从服务器时,应该备份这两个状态文件以及中继日志。它们用来在恢复从服务器的数据后继续进行复制。如果丢失了中继日志但仍然有relay-log.info文件,可以通过检查该文件来确定SQL线程已经执行的主服务器中二进制日志的程度。然后,你可以使用 CHANGE MASTER TOMASTER_LOG_FILEMASTER_LOG_POS的选项告诉Slave从这个位置重新读取的二进制日志。当然,这要求Master服务器上还存在二进制文件。

[转自我自己的老博客,曾写于:2012-10-31 17:20]

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章