1、默认主从复制

Mysql的复制原理大致如下:

  1. 主库记录binlog日志:在每次准备提交事务完成数据更新前,主库将数据更新的事件记录到二进制日志binlog中。主库上的sync_binlog参数控制binlog日志刷新到磁盘。
  2. 从库IO线程将主库的binlog日志复制到其本地的中继日志relay log中:从库会启动一个IO线程,IO线程会跟主库建立连接,然后主库会启动一个特殊的二进制转储线程(binlog dump),二进制转储线程会读取主库上binlog中的事件,它不会一直对事件进行轮询,当它追赶上了主库就会进入睡眠状态,直到主库发送信号量通知其有新事件产生才会被唤醒。
  3. 从库的SQL线程进行重放:从库的SQL线程从中继日志relay log中读取事件并在从库执行,从而实现从库数据的更新。

mysql主从复制_mysql

注意:在老版本mysql中主库上并发的修改操作在从库上只能串行化执行,这也是很多工作负载的性能瓶颈所在。

2、半同步复制

2.1)主从延迟导致数据丢失

Mysql5.5之前的复制是异步的,主库和从库的数据有一定的延迟,这样就存在一个问题:当主库上写入一个事务并提交成功,而从库尚未收到主库推送的binlog日志,如果此时主库宕机造成主库上的事务binlog丢失,此时从库就可能损失这个事务,从而造成主从不一致。

2.2)半同步复制

官方文档:​​MySQL :: MySQL 8.0 Reference Manual :: 17.4.10 Semisynchronous Replication​

为了解决这个问题,Mysql5.5引入了半同步复制机制。半同步复制是从Mysql5.5版本开始,以插件的形式支持的,默认情况下是关闭的,使用时需在配置中打开。

Mysql默认的复制是异步的,主库在将事件写入binlog后即成功返回客户端,但并不知道从库是否以及何时会获取和处理日志。而至于半同步复制,主库在提交后执行事务提交的线程将一直等待,直到至少有一个半同步从库确认已接收到所有事件,从库仅在将事件写入其中继日志(relay log)并刷新到磁盘后,才对接收到事务的事件进行确认。此时,主库收到确认后才会对客户端进行响应。半同步复制保证了事务成功提交后,至少有两份日志记录,一份在主库的binlog上,另一份在至少一个从库的中继日志relay log上,这样就进一步保证了数据的完整性。

1)安装&配置:

A、在Master上装插件:
install plugin rpl_semi_sync_master soname 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled=ON;
在my.cnf配置文件里,加入 rpl_semi_sync_master_enabled = 1

B、在Slave上装插件:
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled =ON;
在my.cnf配置文件里,加入rpl_semi_sync_slave_enabled = 1

C、接下来和异步复制设置步骤一样,这样半同步就算完成。
配置成功后,从的日志里面会有:
121210 7:28:43 [Note] Slave I/O thread: Start semi-sync replication to master 'repl@192.168.222.222:3306' in log 'mysql-bin.000001' at position 107

2)参数:

当所有的Slave崩溃,或则断开,从而Slave接受不到Master的事务,导致M得不到S返回的确认信息,M会一直等待。这里有2个参数可以设置:

Master上:

  • rpl_semi_sync_master_enabled:表示在 master 上已经开启半同步复制模式。
  • rpl_semi_sync_master_timeout :为了防止半同步复制在没有收到S发出的确认发生堵塞,该可以设置一个计时器,用来设置超时,超过这个时间值没有收到信息,则切换到异步复制,执行操作。(默认为10000毫秒,等于10秒,这个参数动态可调,表示主库在某次事务中,如果等待时间超过10秒,那么则降级为异步复制模式,不再等待SLAVE从库。如果主库再次探测到,SLAVE从库恢复了,则会自动再次回到半同步复制模式。)
  • rpl_semi_sync_master_wait_no_slave :当一个事务被提交,但是Master没有Slave连接,这时M不可能收到任何确认信息,但M会在时间限制范围内继续等待。如果没有Slave链接,会切换到异步复制。(是否允许master每个事务提交后都要等待slave的接收确认信号。默认为on,每一个事务都会等待。如果为off,则slave追赶上后,也不会开启半同步复制模式,需要手工开启。)

Slave上:

  • rpl_recovery_rank:当 slave 从库宕机后,假如 Relay-Log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay-log,并且重新从 MASTER 上获取日志,这样保证 relay-log 的完整。默认情况下该功能是关闭的, relay_log_recovery 的值设置为 1 时,将可在 slave从库上开启该功能。
mysql> show variables like '%rpl%';
+------------------------------------+-------+
| Variable_name | Value |
+------------------------------------+-------+
| rpl_recovery_rank | 0 |
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_no_slave | ON |
+------------------------------------+-------+
5 rows in set (0.00 sec)

#slave
mysql> show variables like 'rpl%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_recovery_rank | 0 |
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
3 rows in set (0.00 sec)

3)查看半同步状态:

mysql> show global status like 'rpl_semi%';
+--------------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------------+--------+
| Rpl_semi_sync_master_clients | 1 |
| Rpl_semi_sync_master_net_avg_wait_time | 40203 |
| Rpl_semi_sync_master_net_wait_time | 361832 |
| Rpl_semi_sync_master_net_waits | 9 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 1 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 402 |
| Rpl_semi_sync_master_tx_wait_time | 2011 |
| Rpl_semi_sync_master_tx_waits | 5 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 4 |
+--------------------------------------------+--------+
14 rows in set (0.00 sec)

#slave
mysql> show global status like 'rpl_semi%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.00 sec)

解释:

  • Rpl_semi_sync_master_clients:说明支持和注册半同步复制的已链接Slave数。
  • Rpl_semi_sync_master_status:ON是活动状态(半同步),OFF是非活动状态(异步),要么是他没有启用或则已恢复到异步复制状态。用于指示主服务器使用的是异步复制模式,还是半同步复制模式。
  • Rpl_semi_sync_master_yes_tx:成功提交数量。
  • Rpl_semi_sync_master_no_tx :不成功提交数量。
  • Rpl_semi_sync_slave_status :Slave上的半同步复制状态,ON表示已经被启用,OFF表示非活动状态。

总结:

  • 好处:半同步复制可以有效的限制事务丢失的数量,更好的保证数据的安全和一致性;
  • 坏处:更新、插入、删除的速度要比异步复制要慢,因为多了一个从返回信息给主的步骤。要是出现异常:网络问题或则数据库问题,半同步复制和异步复制就会来回切换,导致主库的更新、插入、删除操作会受到影响。

3、并行复制(multi-threaded slave)

官方文档:

5.6:​​MySQL :: MySQL 5.6 Reference Manual :: 17.1.4.3 Replica Server Options and Variables​

5.7:​​MySQL :: MySQL 5.7 Reference Manual :: 16.1.6.3 Replica Server Options and Variables​

3.1)主从延时问题:

由于主库上可以多客户端并发的写入,当主库的TPS较高时,由于从库的SQL线程是单线程的,导致从库处理速度可能会跟不上主库的处理速度,从而造成了延迟。

可以通过监控 show slave status 命令输出的Seconds_Behind_Master参数的值来检测主从延时:

  • NULL:表示io_thread或是sql_thread有任何一个发生故障;
  • 0:该值为零,表示主从复制良好;
  • 正值:表示主从已经出现延时,数字越大表示从库延迟越严重。

用了mysql主从架构之后,可能会发现,刚写入库的数据结果没查到,所以实际上你要考虑好应该在什么场景下来用这个mysql主从同步,建议是一般在读远远多于写,而且读的时候一般对数据时效性要求没那么高的时候,才用mysql主从同步。一般来说,如果主从延迟较为严重,可以通过如下方式优化:

  1. 架构层面:分库,将一个主库拆分为多个。比如将1个库拆为4个主库,每个主库的写并发就500/s,此时主从延迟可以忽略不计。
  2. 开启mysql支持的并行复制,多个库并行复制。但如果说某个库的写入并发就是特别高,单库写并发达到了2000/s,并行复制还是没意义。28法则,很多时候比如说,就是少数的几个订单表,写入了2000/s,其他几十个表10/s。
  3. 代码层面:重写代码。写代码的同学,要慎重。当时我们其实短期是让那个同学重写了一下代码,插入数据之后直接就更新,不要查询。
  4. 直连主库。如果确实存在插入后立马要求就查询到,然后根据结果(比如某个状态)反过来执行一些操作,则可以对这个查询设置【直连主库】。但不推荐这种方法,这么搞导致读写分离的意义就丧失了。

3.2)并行复制概念:

所谓并行复制,指的是从库开启多个SQL线程,并行读取relay log中不同库的日志,然后并行重放不同库的日志,这是库级别的并行。

1)Mysql5.6中的并行复制

MySQL 5.5版本不支持并行复制。MySQL 5.6版本开始支持并行复制,但是其并行只是基于schema的,也就是基于库的。当有多个库时多个库可以并行进行复制,而库与库之间互不干扰。但多数情况下,可能只有单schema,即只有单个库,那基于schema的复制就没什么用了。

其核心思想是:不同schema下的表并发提交时的数据不会相互影响,即slave节点可以用对relay log中不同的schema各分配一个类似SQL功能的线程,来重放relay log中主库已经提交的事务,保持数据与主库一致。

只需设置参数slave_parallel_workers即可开启并行复制,例如设置 slave_parallel_workers= 4,即有4个SQL Thread(coordinator线程)来进行并行复制。

2)Mysql5.7中的并行复制

而MySQL 5.7版本对并行复制进一步改进,已经支持“真正”的并行复制功能,是基于组提交的并行复制,官方称为enhanced multi-threaded slave(简称MTS),复制延迟问题已经得到了极大的改进。

其核心思想:一个组提交的事务都是可以并行回放(配合binary log group commit);slave机器的relay log中 last_committed相同的事务(sequence_num不同)可以并发执行。

通过设置参数slave_parallel_workers>0并且global.slave_parallel_type=‘LOGICAL_CLOCK’,即可支持一个schema下,slave_parallel_workers个的worker线程并发执行relay log中主库提交的事务。

​https://zhuanlan.zhihu.com/p/49548095​

4、多源复制(Multi-Source Replication)

官方文档:​​https://dev.mysql.com/doc/refman/5.7/en/replication-multi-source.html​

MySQL从5.7版本开始支持多源复制的。MySQL 5.7之前只能实现一主一从、一主多从或者多主多从的复制。如果想实现多主一从的复制,只能使用 MariaDB,但是 MariaDB 又与官方的 MySQL 版本不兼容。MySQL 5.7 开始支持了多主一从的复制方式,也就是多源复制。所以,多源复制至少需要两个Master和一个Slave。

mysql主从复制_数据_02

1)多源复制使用场景

  • 数据分析部门会需要各个业务部门的部分数据做数据分析,这个时候就可以用到多源复制把各个主数据库的数据复制到统一的数据库中。
  • 在从服务器进行数据汇总,如果我们的主服务器进行了分库分表的操作,为了实现后期的一些数据统计功能,往往需要把数据汇总在一起再统计。
  • 在从服务器对所有主服务器的数据进行备份,在MySQL 5.7之前每一个主服务器都需要一个从服务器,这样很容易造成资源浪费,同时也加大了DBA的维护成本,但MySQL 5.7引入多源复制,可以把多个主服务器的数据同步到一个从服务器进行备份。

2)配置多源复制

配置多源复制时,可以将主库配置为使用基于GTID的复制或基于binlog位置的复制。

​https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-howto.html​

​https://dev.mysql.com/doc/refman/5.7/en/replication-howto-masterbaseconfig.html​

 

 参考:

​https://zhuanlan.zhihu.com/p/49548095​