复制支持将来自一个 MySQL 数据库服务器(源)的数据复制到一个或多个 MySQL 数据库服务器(副本)。默认情况下,复制是异步的; 不需要永久连接副本来接收来自源的更新。根据配置,您可以复制数据库中的所有数据库、选定的数据库,甚至选定的表。

在 MySQL 中副本的主要使用场景有:

  • 扩展性方案:采用读写分离模式,在副本上读,在主节点上写入;
  • 数据安全性:在副本上执行数据备份操作,不影响主节点性能;
  • 数据分析:在副本上做数据分析,不影响主节点性能;
  • 离线使用:在长距离场景下,创建本地副本数据,可以减少与远程的服务器频繁交互,提高性能;

还有一些其他的使用场景,可以参考这里:https://dev.mysql.com/doc/refman/5.7/en/replication-solutions.html

一、实现原理

通过 binlog 记录操作事件,实现数据复制。

因为每个副本都是独立的,所以在连接到源的每个副本上都独立地重放源的二进制日志中的更改。
此外,由于每个副本只从源接收二进制日志的副本,因此该副本能够按照自己的速度读取和更新数据库的副本,并且可以随意开始和停止复制过程,而不影响在源或副本端更新到最新数据库状态的能力。

复制功能使用三个主线程实现,一个在源服务器上,两个在副本上:

  • Binary log dump 线程。源创建一个线程,以便在副本连接时将 Binlog 内容发送到一个副本。此线程可以在源的 SHOW PROCESSLIST 的输出中标识为 Binlog Dump 线程。Binlog dump 线程获取源 Binlog 的锁,以读取将发送到副本的每个事件。一旦读取了事件,就会释放锁,甚至在事件发送到副本之前也是如此。

  • Replication I/O 线程:当在复制服务器上发出 START SLAVE 语句时,复制创建一个 I/O 线程,该线程连接到源,并请求源发送记录在其 bin log 中的更新。该线程读取源的 Binlog Dump 线程发送的更新(参见前一项) ,并将它们复制到包含复制的 relay log的本地文件中。此线程的状态在 SHOW SLAVE STATUS 的输出中显示为 Slave_IO_running。

  • Replication SQL线程:副本创建一个 SQL 线程来读取复制 I/O 线程写入的 relay log,并执行其中包含的事务。

一个副本使用两个线程将读取来自源的更新分离开来,并将它们执行到独立的任务中。因此,如果应用事务的过程很慢,那么阅读事务的任务就不会减慢。例如,如果副本服务器已经有一段时间没有运行了,那么当副本启动时,它的 i/o 线程可以从源代码快速获取所有的二进制日志内容,即使 SQL 线程远远落后。如果在 SQL 线程执行所有获取的语句之前,副本停止,那么 i/o 线程至少获取了所有内容,以便事务的安全副本存储在副本的 relay logs 中,为下次副本启动时执行做好准备。

您可以通过将 slave_parallel_workers 系统变量设置为大于0(默认值)的值,为复制上的任务启用进一步的并行化。设置了这个系统变量后,副本将创建指定数量的工作线程来应用事务,外加一个协调器线程来管理它们。如果使用多个复制通道,则每个通道具有这个数量的线程。slave_parallel_workers 将从并行工作线程设置为大于0的副本称为多线程副本。通过这种设置,可以重新尝试失败的事务。

二、监控复制过程

监控语句:SHOW PROCESSLIST

2.1 main 监控(发送方)

在源服务器上执行 SHOW PROCESSLIST 命令:

  1. mysql> SHOW PROCESSLIST\G
  2. *************************** 1. row ***************************
  3. Id: 2
  4. User: root
  5. Host: localhost:32931
  6. db: NULL
  7. Command: Binlog Dump
  8. Time: 94
  9. State: Has sent all binlog to slave; waiting for binlog to
  10. be updated
  11. Info: NULL

这里,线程2是一个 Binlog Dump 线程,服务于一个连接的副本。状态信息表明,所有未完成的更新已发送到副本,源正在等待发生更多更新。如果在源服务器上没有看到 Binlog Dump 线程,这意味着复制没有运行; 也就是说,当前没有连接任何副本。

2.2 slave 监控(接收方)

在 slave服务器上运行 SHOW PROCESSLIST 命令:

mysql> SHOW PROCESSLIST\G
*************************** 1. row ***************************
     Id: 10
   User: system user
   Host:
     db: NULL
Command: Connect
   Time: 11
  State: Waiting for master to send event
   Info: NULL
*************************** 2. row ***************************
     Id: 11
   User: system user
   Host:
     db: NULL
Command: Connect
   Time: 11
  State: Has read all relay log; waiting for the slave I/O
         thread to update it
   Info: NULL

State 信息表明:

  • 线程10是与源服务器通信的 replication I/O 线程;
  • 线程11是处理中继日志中存储的更新的复制 SQL 线程。

在运行 SHOW PROCESSLIST 时,两个线程都处于空闲状态,正在等待进一步的更新。

Time 列中的值可以显示slave与 main 比较的晚期时间。如果 main 经过一段时间后,发现 slave 没有更新,则表明 slave 已经断开了。具体时间设置在系统变量中:

  • net_write_timeout
  • net_retry_count