MySQL半同步复制实践

    科技2025-01-12  8

    目录

    1.主从复制原理2.半同步复制环境搭建2.1 半同步插件安装和配置2.1.1 主库半同步插件安装和配置2.1.2 从库半同步插件安装和配置 2.2 半同步复制测试2.2.1 测试1--简单测试2.2.2 测试2--超时测试 3.参考

    1.主从复制原理

    在MySQL主从复制中,大体上有三个线程,master端有一个dump 线程,slave端有两个线程,i/o 线程和sql线程。

    当有数据写入后,master 端的dump线程将bin log发送到slave端的io线程,i/o线程接收后,将其存放在本地的relay log中。

    sql线程读取relay log,接着重放 event,更新数据。

    主从复制有三种方式:

    异步复制同步复制半同步复制

    其中,同步复制中,master执行一个事务后,要求所有的slave都执行完成后,才会返回给客户端。这样,在性能上,是有影响的。同步复制的优势,就是不丢失数据。缺点,就是复制效率低。 MySQL自身不支持同步复制,需要用第三方工具如DRBD(sync模式)等实现同步复制。

    异步复制中,master 更新操作写入binlog后,就会返回给客户端。不关心,slave 是否接收到binlog,以及是否应用了更新。异步复制的优势,是复制效率高。缺点是,可能会丢失数据。

    半同步复制(semi-sync repication),是介于同步复制和异步复制之间的一种复制方式。主库在执行完客户端提交的事务之后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端(极端情况下,如果等待超时,会退化为异步复制)。相对于异步复制,半同步复制提高了数据的安全性。

    2.半同步复制环境搭建

    下文使用的是单机多实例环境,具体搭建过程可参考单机安装MySQL多实例。

    MySQL版本是 5.7.27。

    MySQL主从集群信息如下:

    角色ipport主库127.0.0.13306从库127.0.0.13307

    2.1 半同步插件安装和配置

    MySQL安装包中,已经自带MySQL半同步插件。

    $ ll /application/mysql/lib/plugin/semi* -rwxr-xr-x. 1 lanyang lanyang 708586 Jun 10 2019 /application/mysql/lib/plugin/semisync_master.so -rwxr-xr-x. 1 lanyang lanyang 152341 Jun 10 2019 /application/mysql/lib/plugin/semisync_slave.so

    2.1.1 主库半同步插件安装和配置

    安装插件

    mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; Query OK, 0 rows affected (0.01 sec) mysql>

    主库开启半同步

    mysql> set global rpl_semi_sync_master_enabled = 1; Query OK, 0 rows affected (0.01 sec) mysql>

    配置半同步超时参数(单位ms)

    mysql> set global rpl_semi_sync_master_timeout = 1000; Query OK, 0 rows affected (0.00 sec) mysql>

    该参数表示主库等待从库ack的时间,如果超时,半同步复制就退化为异步复制。

    此处配置的超时时间是1s。

    在配置文件添加,使其永久生效:

    [mysqld] rpl_semi_sync_master_enabled = 1 rpl_semi_sync_master_timeout = 1000

    查看半同步插件安装和配置状态

    mysql> select * from mysql.plugin; +----------------------+--------------------+ | name | dl | +----------------------+--------------------+ | rpl_semi_sync_master | semisync_master.so | +----------------------+--------------------+ 1 row in set (0.00 sec)

    主库半同步复制的状态参数

    mysql> show global status like '%semi%'; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 0 | | 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 有多少个开启了半同步复制的从库。

    Rpl_semi_sync_master_net_avg_wait_time master等待slave回复的平均网络等待时间。

    Rpl_semi_sync_master_net_wait_time 总网络等待时间。

    Rpl_semi_sync_master_net_waits master等待slave回复总的网络等待次数。

    Rpl_semi_sync_master_tx_avg_wait_time 平均事务等待时间。

    Rpl_semi_sync_master_tx_wait_time 总事务等待时间。

    Rpl_semi_sync_master_tx_waits 总事务等待次数。

    Rpl_semi_sync_master_yes_tx 接收确认次数。

    Rpl_semi_sync_master_no_times 关闭半同步复制的次数。

    Rpl_semi_sync_master_no_tx 查看有多少事务没有使用半同步复制的机制进行复制,也就是master等待超时的次数。

    主库半同步复制的相关参数配置

    mysql> show global variables like '%semi%'; +-------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------+------------+ | rpl_semi_sync_master_enabled | ON | | rpl_semi_sync_master_timeout | 1000 | | 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 | +-------------------------------------------+------------+ 6 rows in set (0.00 sec)

    其中, rpl_semi_sync_master_wait_for_slave_count 表示主库事务提交前,在指定的时间rpl_semi_sync_master_timeout超时之前,必须有这个指定数量的从库确认已接收到。

    如果超时之前,仍然没有得到rpl_semi_sync_master_wait_for_slave_count这个数量的从库确认,则退化为异步复制。

    默认值1,即超时之前,需要有一个从库确认已接收到bin log,事务才可以提交。

    对于 rpl_semi_sync_master_wait_no_slave,表示是否每个事务提交后都需要等待从库的接收确认信号。

    如果为ON(默认是ON),只要指定数量的从库在超时之前确认已接收,则半同步复制会继续。

    如果为OFF,表示在超时之前,没有达到指定数量从库已确认接收。则退化为异步复制。

    2.1.2 从库半同步插件安装和配置

    mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; Query OK, 0 rows affected (0.02 sec) mysql>

    从库开启半同步

    mysql> set global rpl_semi_sync_slave_enabled = 1; Query OK, 0 rows affected (0.00 sec) mysql>

    添加到配置文件使其永久生效:

    [mysqld] rpl_semi_sync_slave_enabled = 1

    配置后,记得重启下i/o线程。

    查看从库上半同步复制状态和参数:

    mysql> show global status like '%semi%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Rpl_semi_sync_slave_status | ON | +----------------------------+-------+ 1 row in set (0.00 sec) mysql> show global variables like '%semi%'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | rpl_semi_sync_slave_enabled | ON | | rpl_semi_sync_slave_trace_level | 32 | +---------------------------------+-------+ 2 rows in set (0.00 sec)

    接着,查看主库上的半同步复制状态:

    mysql> show global status like '%semi%'; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 1 | +--------------------------------------------+-------+ ... ... 14 rows in set (0.00 sec)

    显示已有一个从库通过半同步复制连接到主库。

    2.2 半同步复制测试

    2.2.1 测试1–简单测试

    在主库上写入两条数据:

    mysql> insert into app.test(service_group_name) values('abc001'); Query OK, 1 row affected (0.01 sec) mysql> insert into app.test(service_group_name) values('abc002'); Query OK, 1 row affected (0.00 sec)

    查看主库上的半同步复制状态:

    mysql> show global status like '%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 | 2 | | 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 | 472 | | Rpl_semi_sync_master_tx_wait_time | 472 | | Rpl_semi_sync_master_tx_waits | 1 | | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 2 | +--------------------------------------------+-------+ 14 rows in set (0.00 sec) mysql>

    2.2.2 测试2–超时测试

    (1)停止从库的i/o线程

    停止从库的i/o线程,可以使半同步复制超时。

    mysql> stop slave io_thread; Query OK, 0 rows affected (0.01 sec)

    (2)在主库上写入数据

    mysql> insert into app.test(service_group_name) values('abc003'); Query OK, 1 row affected (1.01 sec) mysql>

    可以看到执行时间1.01s。

    查看此时的半同步复制状态:

    mysql> show global status like '%semi%'; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 0 | | Rpl_semi_sync_master_net_avg_wait_time | 0 | | Rpl_semi_sync_master_net_wait_time | 0 | | Rpl_semi_sync_master_net_waits | 2 | | Rpl_semi_sync_master_no_times | 1 | | Rpl_semi_sync_master_no_tx | 1 | | Rpl_semi_sync_master_status | OFF | | Rpl_semi_sync_master_timefunc_failures | 0 | | Rpl_semi_sync_master_tx_avg_wait_time | 472 | | Rpl_semi_sync_master_tx_wait_time | 472 | | Rpl_semi_sync_master_tx_waits | 1 | | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 2 | +--------------------------------------------+-------+ 14 rows in set (0.01 sec)

    Rpl_semi_sync_master_no_times 关闭半同步的次数为1。

    Rpl_semi_sync_master_no_tx 等待超时的次数,为1.

    Rpl_semi_sync_master_status 半同步状态处于关闭状态。

    (3)从库开启i/o 线程

    mysql> start slave io_thread; Query OK, 0 rows affected (0.00 sec)

    (4)再次查看主库上半同步复制状态

    mysql> show global status like '%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 | 3 | | 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 | 472 | | Rpl_semi_sync_master_tx_wait_time | 472 | | Rpl_semi_sync_master_tx_waits | 1 | | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 2 | +--------------------------------------------+-------+ 14 rows in set (0.00 sec)

    从库复制后,主库半同步复制状态又变为ON。

    3.参考

    16.1.6.2 Replication Source Options and Variables

    Processed: 0.012, SQL: 8