MySQL半同步复制

半同步复制简介

MySQL复制默认情况下是异步的,主库将事件写入binlog并不管从库是否接受并处理它们,如果主库崩溃时,已提交的事务可能没有被传送到从库,因此主从切换可能导致数据丢失。Semisynchronous Replication(半同步复制)则一定程度上保证提交的事务已经传给了至少一个备库。半同步
复制中,仅仅保证事务的已经传递到备库上,但是并不确保已经在备库上执行完成了。半同步复制确实有一定的性能影响,因为需要等待的从库确认。这是对增加数据的完整性的折衷。

工作原理:

  1. 从库连接主库时指明时从库否有半同步能力
  2. 主库启动半同步复制且至少有一个半同步从库,主库线程执行事务提交之后将会阻塞直到任一半同步从库确认接收到该事务的所有事件或者超时
  3. 从库确认接收到事务的所有事件之后写入到中继日志并刷新到磁盘
  4. 如果超时没有任何从库确认事务,主库恢复到异步复制,保障业务的正常使用,直到一台从库追赶上之后,继续切换到半同步模式
  5. 半同步复制必须主从两端同时启用,如任意一端禁止将使用异步复制

当主库被阻塞时(已经提交的事务等待从从库确认),不会向执行事务的session返回信息;当主库阻塞结束后,返回session执行结果。
此时,主库事务已提交,至少一台从库确认接收到事务。

如果主备网络故障或者从库崩溃,主库在事务提交后等待10秒(rpl_semi_sync_master_timeout默认值)后,主从复制将自动降级为异步模式。

半同步复制是通过plugin实现的,master和slave使用不同的plugin。默认情况下没有安装该plugin,插件位于CMAKE_INSTALL_PREFIX/lib/plugin/。安装完插件之后,还需要手动设置系统参数以开启半同步复制模式。

安装配置半同步

[Master]

首先先检查 mysql是否支持动态添加插件
mysql> show variables like 'have_dynamic_loading';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| have_dynamic_loading | YES   |
+----------------------+-------+
1 row in set (0.02 sec)

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

mysql> show variables like '%sem%';
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled       | OFF   |
| 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)

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

mysql> set global rpl_semi_sync_master_timeout=2000;        #毫秒
Query OK, 0 rows affected (0.00 sec)


mysql> show status like '%sem%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 0     |     # 有多少slave设置了半同步模式
| 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     |     # 一共有几次从Semi-sync跌回普通状态
| Rpl_semi_sync_master_no_tx                 | 0     |     # 备库未及时响应的事务次数
| Rpl_semi_sync_master_status                | ON    |     # 主库上Semi-sync是否正常开启
| Rpl_semi_sync_master_timefunc_failures     | 0     |     # 时间函数未正常工作的次数
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |     # 开启Semi-sync,事务返回需要等待的平均时间
| 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.01 sec)


[Slave]

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

mysql> show variables like '%sem%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | OFF   |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
2 rows in set (0.00 sec)

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

然后重启replication(stop slave;start slave;)即可。
一定需要重启,否则master无法确认该slave是否开启了半同步。相同的操作可以在任意多个slave中进行设置。
[slave]

mysql> show status like '%sem%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.01 sec)

[master]

mysql> show status like '%sem%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| Rpl_semi_sync_master_net_avg_wait_time     | 9978  |
| Rpl_semi_sync_master_net_wait_time         | 19957 |
| Rpl_semi_sync_master_net_waits             | 2     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx                 | 2     |
| 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_tx_avg_wait_time:事务因开启Semi_sync,平均需要额外等待的时间
Rpl_semi_sync_master_net_avg_wait_time:事务进入等待队列后,到网络平均等待时间
依据上面两个状态值可以知道,Semi-sync的网络消耗有多大,给某个事务带来的额外的消耗有多大。

Rpl_semi_sync_master_status: 表示主库当前Semi-sync是否正常工作
Rpl_semi_sync_slave_status: 表示从库当前Semi-sync是否正常工作

Rpl_semi_sync_master_no_times:可以知道一段时间内,Semi-sync是否有超时失败过,该计数器则记录了这样的失败次数。

Rplsemi_sync_master_wait_pos_backtraverse:在semisync_master中,维护了这样的两个变量wait_file_name和waitfile_pos,当主库上多个事务都在等待从库的响应时,这两个变量记录了所有等待中,最小的那一个Binlog位置。如果这时一个新的事务加入等待,并且该事务需要等待的Binlog比waitfile_name和waitfile_pos还小的话,则更新这两个值,并将Rpl_semi_sync_master_wait_pos_backtraverse值自增1。

整理自网络

Svoid
2015-01-29
发布了54 篇原创文章 · 获赞 5 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章