MySQL主从复制之半同步(semi-sync replication)
阅读原文时间:2023年07月08日阅读:3
  • GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
  • MASTER节点在执行完客户端提交的事务后不是立刻返回结果给客户端,而是等待至少一个SLAVE节点接收并写到relay log中才返回给客户端。

  • 半同步相对于异步复制而言,提高了数据的安全性,同时也造成了一定程度的延迟,这个延迟最少是一个TCP往返的时间。所以,半同步复制最好在低延时的网络中使用。

  • MySQL从5.5开始就支持半同步复制,在5.7.2版本的时候对半同步复制进行了一次改进;原先的半同步策略为 AFTER_COMMIT 改进后的策略为 AFTER_SYNC 两者的差异在于SLAVE节点ACK应答MASTER的时机不同。

  • AFTER_COMMIT 模式介绍

MASTER将每个事务写入到二进制日志并刷盘保存,同时将事务发送给SLAVE,然后将事务提交给存储引擎处理并进行提交,然后等待SLAVE返回确认信息,在收到确认信息后,MASTER将结果返回给客户端,然后当前客户端可以继续工作。

  • AFTER_SYNC 模式介绍

MASTER将每个事务写入到二进制日志并刷盘保存,同时将事务发送给SLAVE,然后等待SLAVE返回确认信息,收到确认信息后,将事务提交给存储引擎处理并进行提交,并将结果返回给客户端,然后当前客户端可以继续工作。

  • 对于第一种 AFTER_COMMIT 方式,当前客户端只有在服务器向存储引擎提交数据并收到SLAVE返回的确认后,才会收到事务的返回结果。在事务提交之后收到SLAVE返回确认信息之前,此刻其他客户端可以看到当前客户端提交的事务信息。

如果SLAVE节点由于网络等原因并未收到MASTER节点传递过来的事务,而MASTER节点此刻crash了。HA进行故障转移,客户端都连到SLAVE节点上,这时先前在MASTER节点看到的事务在SLAVE节点并未看到,就会发生事务丢失的情况。

  • 对于第二种 AFTER_SYNC 方式,当事务被SLAVE确认后MASTER在存储引擎层面进行提交事务后,所有客户端才能看到事务造成的数据更改。因此,所有客户端在MASTER上同一时刻看到是相同的数据。

当MASTER节点crash的情况下,所有在MASTER上提交的事务都被复制到SLAVE(保存到中继日志中)。 MASTER服务器意外crash。此刻HA进行故障转移到SALVE后,客户端看到的数据是无损的,因为SLAVE是最新的。

注意,然而,在这种情况下,MASTER不能直接恢复使用,因为它的二进制日志可能包含未提交的事务,此刻当二进制日志恢复并用于业务需求时,可能会导致与SLAVE的冲突。

  • 方式1:半同步以插件的形式存在,咱们可以直接在线开启即可(本次采用这次方式)

    主节点开启

    [root@GreatSQL][(none)]>INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
    Query OK, 0 rows affected (0.02 sec)

    从节点开启

    [root@GreatSQL][(none)]>INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
    Query OK, 0 rows affected (0.02 sec)

    PS:一般情况下所有节点都同步部署master和slave插件,这样故障切换的时候会比较方便处理

  • 方式2:在my.cnf配置中进行开启

    主从节点都同步配置开启

    plugin-load="rpl_semi_sync_master=semisync_master.so;rpl_sync_slave=semisync_slave.so"
    rpl_semi_sync_master_enabled=1
    rpl_semi_sync_slave_enabled=1

  • 方式1:查询plugin

    主节点查看

    [root@GreatSQL][test]>show plugins;
    | rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL |

    从节点查看

    [root@GreatSQL][(none)]>show plugins;
    | rpl_semi_sync_slave | ACTIVE | REPLICATION | semisync_slave.so | GPL |

  • 方式二:查询information_schema.plugins信息更全面

    主节点信息

    (Thu Feb 17 03:03:12 2022)[root@GreatSQL][(none)]>select * from information_schema.plugins where plugin_name like "%semi%"\G;
    * 1. row *
    PLUGIN_NAME: rpl_semi_sync_master
    PLUGIN_VERSION: 1.0
    PLUGIN_STATUS: ACTIVE
    PLUGIN_TYPE: REPLICATION
    PLUGIN_TYPE_VERSION: 4.0
    PLUGIN_LIBRARY: semisync_master.so
    PLUGIN_LIBRARY_VERSION: 1.10
    PLUGIN_AUTHOR: Oracle Corporation
    PLUGIN_DESCRIPTION: Semi-synchronous replication master
    PLUGIN_LICENSE: GPL
    LOAD_OPTION: ON
    1 row in set (0.00 sec)

    ERROR:
    No query specified

    从节点信息

    (Thu Feb 17 16:05:19 2022)[root@GreatSQL][(none)]>select * from information_schema.plugins where plugin_name like "%semi%"\G;
    * 1. row *
    PLUGIN_NAME: rpl_semi_sync_slave
    PLUGIN_VERSION: 1.0
    PLUGIN_STATUS: ACTIVE
    PLUGIN_TYPE: REPLICATION
    PLUGIN_TYPE_VERSION: 4.0
    PLUGIN_LIBRARY: semisync_slave.so
    PLUGIN_LIBRARY_VERSION: 1.10
    PLUGIN_AUTHOR: Oracle Corporation
    PLUGIN_DESCRIPTION: Semi-synchronous replication slave
    PLUGIN_LICENSE: GPL
    LOAD_OPTION: ON
    1 row in set (0.00 sec

  • 因为上面是在线安装插件的,所以插件安装完成后,服务还要启动一下

    主节点启用半同步复制

    [root@GreatSQL][test]>SET GLOBAL rpl_semi_sync_master_enabled = on;
    Query OK, 0 rows affected (0.00 sec)

    从节点启用半同步复制

    [root@GreatSQL][(none)]>SET GLOBAL rpl_semi_sync_slave_enabled = on;
    Query OK, 0 rows affected (0.00 sec)

  • 以上设置完成后,从节点重启IO线程

    (Mon Feb 14 15:19:58 2022)[root@GreatSQL][(none)]>
    (Mon Feb 14 15:19:58 2022)[root@GreatSQL][(none)]>STOP SLAVE IO_THREAD;
    Query OK, 0 rows affected, 1 warning (0.01 sec)

    (Mon Feb 14 15:21:41 2022)[root@GreatSQL][(none)]>START SLAVE IO_THREAD;
    Query OK, 0 rows affected, 1 warning (0.01 sec)

    主节点

    [root@GreatSQL][test]>show status like 'Rpl_semi_sync_master_status';
    +-----------------------------+-------+
    | Variable_name | Value |
    +-----------------------------+-------+
    | Rpl_semi_sync_master_status | ON |
    +-----------------------------+-------+
    1 row in set (0.00 sec)

    从节点

    [root@GreatSQL][(none)]>show status like 'Rpl_semi_sync_slave_status';
    +----------------------------+-------+
    | Variable_name | Value |
    +----------------------------+-------+
    | Rpl_semi_sync_slave_status | ON |
    +----------------------------+-------+
    1 row in set (0.01 sec)

  • 查看主节点error.log,可以看出来从节点已经启用半同步复制了

    关键信息 Start semi-sync binlog_dump to slave (server_id: 3306)

    2022-02-14T02:16:35.411061-05:00 13 [Note] [MY-010014] [Repl] While initializing dump thread for slave with UUID <652ade08-8b1c-11ec-9f62-00155dcff90a>, found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(12).
    2022-02-14T02:16:35.411236-05:00 13 [Note] [MY-010462] [Repl] Start binlog_dump to master_thread_id(13) slave_server(3306), pos(, 4)
    2022-02-14T02:16:35.411263-05:00 13 [Note] [MY-011170] [Repl] Start asynchronous binlog_dump to slave (server_id: 3306), pos(, 4).
    2022-02-14T02:16:35.411419-05:00 12 [Note] [MY-011171] [Repl] Stop asynchronous binlog_dump to slave (server_id: 3306).
    2022-02-14T02:19:33.913084-05:00 9 [Note] [MY-011130] [Repl] Semi-sync replication initialized for transactions.
    2022-02-14T02:19:33.913133-05:00 9 [Note] [MY-011142] [Repl] Semi-sync replication enabled on the master.
    2022-02-14T02:19:33.913638-05:00 0 [Note] [MY-011166] [Repl] Starting ack receiver thread.
    2022-02-14T02:21:46.899725-05:00 14 [Note] [MY-010014] [Repl] While initializing dump thread for slave with UUID <652ade08-8b1c-11ec-9f62-00155dcff90a>, found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(13).
    2022-02-14T02:21:46.899894-05:00 14 [Note] [MY-010462] [Repl] Start binlog_dump to master_thread_id(14) slave_server(3306), pos(, 4)
    2022-02-14T02:21:46.899953-05:00 14 [Note] [MY-011170] [Repl] Start semi-sync binlog_dump to slave (server_id: 3306), pos(, 4).

以上,MySQL半同步复制搭建完毕!

# 主节点参数信息
[root@GreatSQL][test]>show variables like '%Rpl%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_read_size                             | 8192       |
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 10000      |
| rpl_semi_sync_master_trace_level          | 32         |
| rpl_semi_sync_master_wait_for_slave_count | 1          |
| rpl_semi_sync_master_wait_no_slave        | ON         |
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |
| rpl_stop_slave_timeout                    | 31536000   |
+-------------------------------------------+------------+
8 rows in set (0.00 sec)
  • 部分参数简单说明

参数名

用途

rpl_semi_sync_master_enabled

是否开启半同步复制,ON为开启,OFF为关闭

rpl_semi_sync_master_timeout

Master等待Slave的ack回复的超时时间,默认为10秒(基本单位毫秒)

rpl_semi_sync_master_trace_level

调试级别

rpl_semi_sync_master_wait_for_slave_count

Master提交后需要的ACK回复的数量。如果Slave数量大于等于这个值,那么Master就正常,如果低于这个值,Master可能会在事务提交阶段发生一次超时等待,当等待超过参数(rpl_semi_sync_master_timeout)设定时,Master就转为异步模式

rpl_semi_sync_master_wait_no_slave

就是在超时时间内,如果Slave宕机的数量超过了应该要收到的ack数量,Master是否降级为异步复制

rpl_semi_sync_master_wait_point

半同步的方式是哪一种,默认是 AFTER_SYNC ,5.7.2之前是AFTER_COMMIT

# 从节点参数信息
[root@GreatSQL][test]>show variables like '%Rpl%';
+---------------------------------+----------+
| Variable_name                   | Value    |
+---------------------------------+----------+
| rpl_read_size                   | 8192     |
| rpl_semi_sync_slave_enabled     | ON       |
| rpl_semi_sync_slave_trace_level | 32       |
| rpl_stop_slave_timeout          | 31536000 |
+---------------------------------+----------+
4 rows in set (0.00 sec)
  • 部分参数简单说明

参数名

用途

rpl_semi_sync_master_enabled

是否开启半同步复制,ON为开启,OFF为关闭

rpl_semi_sync_slave_trace_level

调试级别

  • 主节点查看

    [root@GreatSQL][test]> show status like '%Rpl_semi%';
    +--------------------------------------------+-------+
    | Variable_name | Value |
    +--------------------------------------------+-------+
    | Rpl_semi_sync_master_clients | 1 |
    | Rpl_semi_sync_master_net_avg_wait_time | 0 |
    | Rpl_semi_sync_master_net_wait_time | 0 |
    | Rpl_semi_sync_master_net_waits | 0 |
    | Rpl_semi_sync_master_no_times | 0 |
    | Rpl_semi_sync_master_no_tx | 0 |
    | Rpl_semi_sync_master_status | ON |
    | Rpl_semi_sync_master_timefunc_failures | 0 |
    | Rpl_semi_sync_master_tx_avg_wait_time | 0 |
    | Rpl_semi_sync_master_tx_wait_time | 0 |
    | Rpl_semi_sync_master_tx_waits | 0 |
    | Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
    | Rpl_semi_sync_master_wait_sessions | 0 |
    | Rpl_semi_sync_master_yes_tx | 0 |
    +--------------------------------------------+-------+
    14 rows in set (0.00 sec)

  • 部分参数用途简要说明

参数名

用途

Rpl_semi_sync_master_clients

当前有多少个从库被设置为半同步模式,不包含异步复制的Slave实例

Rpl_semi_sync_master_net_avg_wait_time

等待从库返回ACK确认消息的平均时间(单位:ms)

Rpl_semi_sync_master_net_wait_time

等到从库返回ACK确认消息的总时间(单位:ms)

Rpl_semi_sync_master_net_waits

等待从库返回ACK确认消息的总次数

Rpl_semi_sync_master_no_tx

事务没有得到从库返回确认消息就提交的次数

Rpl_semi_sync_master_status

当半同步复制开启后,该变量用来动态地显示半同步复制的状态。当值为OFF,表明当前处于异步复制下; 当等待从库返回确认消息时间超过 rpl_semi_sync_master_timeout值后修改为OFF。当值设置为ON,表明当前处于半同步复制下。当从库追赶上主库后修改为ON。

Rpl_semi_sync_master_timefunc_failures

调用函数gettimeofday()失败的次数

Rpl_semi_sync_master_tx_avg_wait_time

MASTER上平均每个事务等待时长

Rpl_semi_sync_master_tx_wait_time

MASTER上事务等待的总时长

Rpl_semi_sync_master_tx_waits

MASTER上事务等待的次数

Rpl_semi_sync_master_wait_pos_backtraverse

MASTER等待事件的二进制坐标低于之前等待事件的总次数。当事务开始等待回复的顺序与其二进制日志事件的写入顺序不同时,就会发生这种情况。这种情况在关闭binlog_order_commit 的情况下可能会出现。

Rpl_semi_sync_master_wait_sessions

当前等待从库返回确认消息的回话数

Rpl_semi_sync_master_yes_tx

Slave节点确认成功提交的事务数

# 从节点转态信息
show global status like '%semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)
  • 参数简单说明

参数名

用途

Rpl_semi_sync_slave_status

动态参数,ON表示在用半同步复制,OFF表示异步复制

  • 半同步是否会降级为异步复制?是会的。

  • 当半同步复制发生超时时(由rpl_semi_sync_master_timeout参数控制,单位是毫秒,默认为10000,即10s),会暂时关闭半同步复制,转而使用异步复制。

  • 当MASTER DUMP 线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout内,收到了从库的响应,则主从又重新恢复为半同步复制。

    1.从节点暂时先关掉IO线程

    [root@GreatSQL][(none)]>STOP SLAVE IO_THREAD;
    Query OK, 0 rows affected, 1 warning (0.02 sec)

    2.主节点写入几条测试数据

    [root@GreatSQL][test]>insert into ptype values(4,'4','4'),(5,'5','5'),(6,'6','6');
    Query OK, 3 rows affected (0.02 sec)

    3.等待10s后查看复制状态,半同步已经关掉了

    [root@GreatSQL][test]>show status like 'Rpl_semi_sync_slave_status';
    +----------------------------+-------+
    | Variable_name | Value |
    +----------------------------+-------+
    | Rpl_semi_sync_slave_status | OFF |
    +----------------------------+-------+
    1 row in set (0.00 sec)

    4.从节点开启IO线程

    [root@GreatSQL][(none)]>START SLAVE IO_THREAD;
    Query OK, 0 rows affected, 1 warning (0.02 sec)

    5.再次查看复制状态,半同步复制自动开启了

    [root@GreatSQL][test]>show status like 'Rpl_semi_sync_slave_status';
    +----------------------------+-------+
    | Variable_name | Value |
    +----------------------------+-------+
    | Rpl_semi_sync_slave_status | ON |
    +----------------------------+-------+
    1 row in set (0.00 sec)

Enjoy GreatSQL

文章推荐:

GreatSQL季报(2021.12.26)

https://mp.weixin.qq.com/s/FZ_zSBHflwloHtZ38YJxbA

技术分享|sysbench 压测工具用法浅析

https://mp.weixin.qq.com/s/m16LwXWy9bFt0i99HjbRsw

故障分析 | linux 磁盘io利用率高,分析的正确姿势

https://mp.weixin.qq.com/s/7cu_36jfsjZp1EkVexkojw

技术分享|闪回在MySQL中的实现和改进

https://mp.weixin.qq.com/s/6jepwEE0DnYUpjMYO17VtQ

万答#20,索引下推如何进行数据过滤

https://mp.weixin.qq.com/s/pt6mr3Ge1ya2aa6WlrpIvQ

关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

Gitee:

https://gitee.com/GreatSQL/GreatSQL

GitHub:

https://github.com/GreatSQL/GreatSQL

Bilibili:

https://space.bilibili.com/1363850082/video

微信&QQ群:

可搜索添加GreatSQL社区助手微信好友,发送验证信息“加群”加入GreatSQL/MGR交流微信群

QQ群:533341697

微信小助手:wanlidbc

本文由博客一文多发平台 OpenWrite 发布!