阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

MySQL半同步复制原理与配置详解

128次阅读
没有评论

共计 7202 个字符,预计需要花费 19 分钟才能阅读完成。

一、异步、同步和半同步复制概念

异步复制(Asynchronous replication),MySQL 默认的复制是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理。原理最简单,性能最好,但是主从之间数据不一致的概率很大。

全同步复制(Fully synchronous replication),指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。

半同步复制(Semisynchronous replication),介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到 relay log 中才返回给客户端。相对于异步复制,半同步复制牺牲了一定的性能,提高了数据的安全性。

二、半同步复制原理

默认情况下,MySQL 的主从复制是异步的,异步复制可以提供最佳的性能,主库把 binlog 日志发送给从库,然后将结果返回给客户端,并不会验证从库是否接收完毕。这也就意味着有可能出现当主库或从库发生故障的时候,从库没有接收到主库发送过来的 binlog 日志,导致主库和从库的数据不一致,甚至在恢复时造成数据的丢失。

为了解决上述出现的问题,MySQL 5.5 引入了一种半同步复制模式。该模式可以确保从库接收完主库发送的 binlog 日志文件并写入到自己的中继日志 relay log 里,然后会给主库一个反馈,告诉主库已经接收完毕,这时主库才返回结果给客户端告知操作完成。当出现从库响应超时情况时,主库会暂时切换到异步复制模式,直到下一次同步没有超时转为半同步复制为止。(master 的 dump 线程除了发送 binlog 数据到 slave,还承担了接收 slave 的 ack 工作。如果出现异常,没有收到 ack,那么将自动降为普通的异步复制,直到异常修复)

  三、半同步复制 –MySQL5.7 版

MySQL5.5 半同步复制带来的新问题:

  1)如果有故障发生,会切换为异步的复制。那么从库出现数据不一致的几率会减少,并不是完全消失。

  2)主机 dump 线程承担的工作变多了(发送 binlog 数据到 slave,接收 slave 的 ack。两者是串行的,dump 线程必须等待 slave 返回 ack 之后才会传送下一个 events 事务。dump 线程是整个半同步提高性能的瓶颈),这样显然会降低整个数据库的性能。

  3)在 MySQL 5.5 和 5.6 使用 after_commit 的模式下, 如果 slave 没有收到事务,也就是还没有写入到 relay log 之前,网络出现异常或者不稳定,此时刚好 master 挂了,系统切换到从库,两边的数据就会出现不一致,slave 会少一个事务的数据。

在此情况下,MySQL5.7 的半同步复制技术升级为全新的 Loss-less Semi-Synchronous Replication 架构,新版本的 semi sync 增加了 rpl_semi_sync_master_wait_point 参数, 来控制半同步模式下主库在返回结果给会话之前提交事务的方式。

该参数有两个值:

  1)AFTER_COMMIT(5.5,5.6 默认值)

master 将每个事务写入 binlog 之后,先提交事务,然后将 binlog 数据传递到 slave 并刷新到磁盘 (relay log)。接着 master 等待 slave 反馈收到 relay log,只有收到 ack 之后 master 才将 commit OK 结果反馈给客户端。如图一所示。

MySQL 半同步复制原理与配置详解                  MySQL 半同步复制原理与配置详解

  2)AFTER_SYNC(5.7 默认值)

master 将每个事务写入 binlog,然后将 binlog 数据传递到 slave 并刷新到磁盘 (relay log)。master 等待 slave 反馈接收到 relay log 的 ack 之后,再提交事务并且返回 commit OK 结果给客户端。即使主库 crash 了,所有在主库上已经提交的事务都能保证已经同步到 slave 的 relay log 中。如图二所示。

MySQL5.7 的半同步复制引入 after_sync 模式,主要是解决了 after_commit 导致的主库 crash 后主从之间数据不一致的问题。在引入 after_sync 模式后,所有提交的数据都已经被复制,故障切换时数据一致性将得到提升。(另外,在 5.7 版本的 semi sync 框架中,独立出一个 ack collector thread,专门用于接收 slave 的反馈信息。这样 master 上有两个线程独立工作,可以同时发送 binlog 到 slave,和接收 slave 的反馈)

四、半同步复制的安装

开启半同步复制,必须是 MySQL5.5 以上版本并且已经搭建好普通的主从异步复制。此处以 MySQL5.5 版本演示,如下所示:

1、安装半同步插件

# 半同步功能主要是下面两个插件
[root@master ~]# ls -l /application/mysql/lib/plugin/
……
-rwxr-xr-x 1 mysql mysql 173396 Sep 15  2017 semisync_master.so
-rwxr-xr-x 1 mysql mysql  94066 Sep 15  2017 semisync_slave.so

# 分别在主从库加载上面两个插件
master:
mysql> install plugin rpl_semi_sync_master soname ‘semisync_master.so’;
slave:
mysql> install plugin rpl_semi_sync_slave soname ‘semisync_slave.so’;

# 查看插件是否加载成功,有两种方法
1)mysql> show plugins;
| rpl_semi_sync_master    | ACTIVE  | REPLICATION        | semisync_master.so | GPL    |2)mysql> select plugin_name,plugin_status from information_schema.plugins where plugin_name like ‘%semi%’;
+———————-+—————+| plugin_name          | plugin_status |
+———————-+—————+| rpl_semi_sync_master | ACTIVE        |
+———————-+—————+1 row in set (0.10 sec)

2、开启半同步复制

在安装完插件后,半同步复制默认是关闭的,这时需设置参数来开启半同步。

mater:
mysql> set global rpl_semi_sync_master_enabled = 1;
slave:
mysql> set global rpl_semi_sync_slave_enabled = 1;
# 以上的启动方式是在命令行操作,是临时生效的;永久生效需将如下设置写在配置文件中。
master:
plugin-load = rpl_semi_sync_master=semisync_master.so  #此项可以让 plugin 在任何时候都被 mysql 加载
rpl_semi_sync_master_enabled = 1
slave:
plugin-load = rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled = 1
# 在有的高可用架构下,master 和 slave 需同时启动,以便在切换后能继续使用半同步复制
plugin-load = “rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so”
rpl-semi-sync-master-enabled = 1
rpl-semi-sync-slave-enabled = 1

3、重启 slave 上的 IO 线程使半同步生效

mysql> stop slave io_thread;

mysql> start slave io_thread;
# 如果没有重启,则默认还是异步复制,重启后,slave 会在 master 上注册为半同步复制的 slave 角色。

# 查看半同步是否在运行
master:
mysql> show status like ‘Rpl_semi_sync_master_status’;
+—————————–+——-+
| Variable_name              | Value |
+—————————–+——-+
| Rpl_semi_sync_master_status | ON    |
+—————————–+——-+

slave:
mysql> show status like ‘Rpl_semi_sync_slave_status’;
+—————————-+——-+
| Variable_name              | Value |
+—————————-+——-+
| Rpl_semi_sync_slave_status | ON    |
+—————————-+——-+

4、半同步复制测试

master:
mysql> create database db;
mysql> use db
Database changed
mysql> create table t1(id int);
mysql> insert into t1 values(1);
mysql> select * from t1;
+——+| id  |+——+|    1 |+——+1 row in set (0.00 sec)
slave:
mysql> select * from db.t1;
+——+| id  |+——+|    1 |+——+1 row in set (0.00 sec)

# 可以看到数据很快同步到了从库上,下面关闭 io_thread 测试
slave:
mysql> stop slave io_thread;
Query OK, 0 rows affected (0.00 sec)
master:
mysql> insert into t1 values(2);  #此处有一个 10s 的超时等待时间,超时后转为异步插入
Query OK, 1 row affected (10.11 sec)
mysql> show status like ‘Rpl_semi_sync_master_status’;  #半同步已失效
+—————————–+——-+| Variable_name              | Value |
+—————————–+——-+| Rpl_semi_sync_master_status | OFF  |
+—————————–+——-+
slave:
mysql> show status like ‘Rpl_semi_sync_slave_status’;  #从库的半同步也失效
+—————————-+——-+| Variable_name              | Value |
+—————————-+——-+| Rpl_semi_sync_slave_status | OFF  |
+—————————-+——-+1 row in set (0.01 sec)
slave:
mysql> start slave io_thread;  #从库开启 io 线程
Query OK, 0 rows affected (0.00 sec)
master:
mysql> show status like ‘Rpl_semi_sync_master_status’;  #又重新转为半同步复制
+—————————–+——-+| Variable_name              | Value |
+—————————–+——-+| Rpl_semi_sync_master_status | ON    |
+—————————–+——-+1 row in set (0.00 sec)
slave:
mysql> select * from db.t1;  #从库上数据已同步
+——+| id |+——+| 1 || 2 |+——+2 rows in set (0.00 sec)

5、其他说明

  1)环境变量

mysql> show variables like ‘%semi%’;
+————————————+——-+
| Variable_name                      | Value |
+————————————+——-+
| 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    |
+————————————+——-+
4 rows in set (0.00 sec)

rpl_semi_sync_master_enabled=ON  表示开启半同步复制

rpl_semi_sync_master_timeout=10000  单位为毫秒,即 10 秒超时,将切换为异步复制

rpl_semi_sync_master_wait_no_slave  表示是否允许 master 每个事务都要等待 slave 接收确认。默认为 ON,每一个事务都会等待,如果 slave crash 后,当 slave 追赶上 master 的日志时,可以自动的切换为半同步方式。如果为 OFF, 则 slave 追赶上后,也不会采用半同步的方式复制了,需要手工配置。

rpl_semi_sync_master_trace_level=32  表示用于开启半同步复制时的调试级别,默认 32

补充:

rpl_semi_sync_master_wait_for_slave_count  MySQL 5.7.3 引入的,该变量设置主库需要等待多少个 slave 应答,才能返回给客户端,默认为 1。

  2)状态变量

mysql> show status like ‘%semi%’;
+——————————————–+——–+
| Variable_name                              | Value  |
+——————————————–+——–+
| Rpl_semi_sync_master_clients              | 1      |
| Rpl_semi_sync_master_net_avg_wait_time    | 21014  |
| Rpl_semi_sync_master_net_wait_time        | 126089 |
| Rpl_semi_sync_master_net_waits            | 6      |
| 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      | 2186  |
| Rpl_semi_sync_master_tx_wait_time          | 4373  |
| Rpl_semi_sync_master_tx_waits              | 2      |
| 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)

Rpl_semi_sync_master_status  标记 master 现在是否是半同步复制状态

Rpl_semi_sync_master_clients  记录支持半同步的 slave 的个数

Rpl_semi_sync_master_yes_tx  master 成功接收到 slave 的回复的次数

Rpl_semi_sync_master_no_tx  master 没有收到 slave 的回复而提交的次数

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-01-22发表,共计7202字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中