MySQL5.7半同步机制


所谓半同步机制,master节点只要确认有至少一个slave节点接收到了事物,即可向客户端返回操作成功的信息,master节点甚至不需要等待slave节点也成功执行完这个事物,只要至少有一个slave节点接收到这个事物,并且将之成功写入到本地的中继日志文件,就算成功。

一,MySQL的半同步复制是以插件形式提供,查看目前是否安装


  1. (root@localhost) [(none)]> show plugins;
  2. +----------------------------+----------+--------------------+---------+---------+
  3. | Name | Status | Type | Library | License |
  4. +----------------------------+----------+--------------------+---------+---------+
  5. | binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
  6. | mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL |
  7. | sha256_password | ACTIVE | AUTHENTICATION | NULL | GPL |
  8. | MEMORY | ACTIVE | STORAGE ENGINE | NULL | GPL |
  9. | InnoDB | ACTIVE | STORAGE ENGINE | NULL | GPL |
  10. | INNODB_TRX | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  11. | INNODB_LOCKS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  12. | INNODB_LOCK_WAITS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  13. | INNODB_CMP | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  14. | INNODB_CMP_RESET | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  15. | INNODB_CMPMEM | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  16. | INNODB_CMPMEM_RESET | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  17. | INNODB_CMP_PER_INDEX | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  18. | INNODB_CMP_PER_INDEX_RESET | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  19. | INNODB_BUFFER_PAGE | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  20. | INNODB_BUFFER_PAGE_LRU | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  21. | INNODB_BUFFER_POOL_STATS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  22. | INNODB_TEMP_TABLE_INFO | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  23. | INNODB_METRICS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  24. | INNODB_FT_DEFAULT_STOPWORD | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  25. | INNODB_FT_DELETED | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  26. | INNODB_FT_BEING_DELETED | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  27. | INNODB_FT_CONFIG | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  28. | INNODB_FT_INDEX_CACHE | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  29. | INNODB_FT_INDEX_TABLE | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  30. | INNODB_SYS_TABLES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  31. | INNODB_SYS_TABLESTATS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  32. | INNODB_SYS_INDEXES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  33. | INNODB_SYS_COLUMNS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  34. | INNODB_SYS_FIELDS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  35. | INNODB_SYS_FOREIGN | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  36. | INNODB_SYS_FOREIGN_COLS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  37. | INNODB_SYS_TABLESPACES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  38. | INNODB_SYS_DATAFILES | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  39. | INNODB_SYS_VIRTUAL | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
  40. | MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
  41. | PERFORMANCE_SCHEMA | ACTIVE | STORAGE ENGINE | NULL | GPL |
  42. | CSV | ACTIVE | STORAGE ENGINE | NULL | GPL |
  43. | MyISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
  44. | ARCHIVE | ACTIVE | STORAGE ENGINE | NULL | GPL |
  45. | partition | ACTIVE | STORAGE ENGINE | NULL | GPL |
  46. | FEDERATED | DISABLED | STORAGE ENGINE | NULL | GPL |
  47. | BLACKHOLE | ACTIVE | STORAGE ENGINE | NULL | GPL |
  48. | ngram | ACTIVE | FTPARSER | NULL | GPL |
  49. +----------------------------+----------+--------------------+---------+---------+
  50. 44 rows in set (0.00 sec)
二,本例目前还没有安装,查看plugin目录位置

  1. (root@localhost) [(none)]> show variables like 'plugin_dir';
  2. +---------------+------------------------------+
  3. | Variable_name | Value |
  4. +---------------+------------------------------+
  5. | plugin_dir | /usr/local/mysql/lib/plugin/ |
  6. +---------------+------------------------------+
  7. 1 row in set (0.00 sec)
三,在plugin目录下有两个与半同步相关的插件

  1. [root@oracle11gtest plugin]# ls -al semisync*
  2. -rwxr-xr-x 1 root root 688816 Feb 6 19:44 semisync_master.so
  3. -rwxr-xr-x 1 root root 150555 Feb 6 19:44 semisync_slave.so
四,在master端安装semisync_master.so,在slave端安装semisync_slave.so

  1. (root@localhost) [(none)]> install plugin rpl_semi_sync_master SONAME 'semisync_master.so' ;
  2. Query OK, 0 rows affected (0.04 sec)

  3. (root@localhost) [(none)]> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so';
  4. Query OK, 0 rows affected (0.01 sec)
五,安装好之后分别用show plugins命令check下

六,修改主端半同步相关参数

  1. (root@localhost) [(none)]> show variables like '%rpl_semi_sync%';
  2. +-------------------------------------------+------------+
  3. | Variable_name | Value |
  4. +-------------------------------------------+------------+
  5. | rpl_semi_sync_master_enabled | OFF |
  6. | rpl_semi_sync_master_timeout | 10000 |
  7. | rpl_semi_sync_master_trace_level | 32 |
  8. | rpl_semi_sync_master_wait_for_slave_count | 1 |
  9. | rpl_semi_sync_master_wait_no_slave | ON |
  10. | rpl_semi_sync_master_wait_point | AFTER_SYNC |
  11. +-------------------------------------------+------------+
  12. 6 rows in set (0.00 sec)

  13. (root@localhost) [(none)]> set global rpl_semi_sync_master_enabled=1;  ---用于控制是否在主端启用半同步复制,
  14. Query OK, 0 rows affected (0.00 sec)

  15. (root@localhost) [(none)]> set global rpl_semi_sync_master_timeout=3000;  ---用于指导主端等待slave响应的时间,单位是毫秒,我这里设为3秒
  16. Query OK, 0 rows affected (0.00 sec)
七,修改slave端半同步相关参数

  1. (root@localhost) [(none)]> show variables like '%rpl_semi_sync%';
  2. +---------------------------------+-------+
  3. | Variable_name | Value |
  4. +---------------------------------+-------+
  5. | rpl_semi_sync_slave_enabled | OFF |
  6. | rpl_semi_sync_slave_trace_level | 32 |
  7. +---------------------------------+-------+
  8. 2 rows in set (0.01 sec)

  9. (root@localhost) [(none)]> set global rpl_semi_sync_slave_enabled=1; ---用于控制是否在slave端启用半同步复制,
  10. Query OK, 0 rows affected (0.00 sec)
八,重启slave节点的io_thread线程,目的是让slave重新连接master,注册成为半同步的slave身份

  1. (root@localhost) [(none)]> stop slave io_thread;
  2. Query OK, 0 rows affected (0.01 sec)

  3. (root@localhost) [(none)]> start slave io_thread;
  4. Query OK, 0 rows affected (0.00 sec)
九,测试

在master端插入数据
insert into oms3.gl values('zg');
  1. insert into oms3.gl values('gl');
查看slave是否应用

  1. (root@localhost) [(none)]> select * from oms3.gl;
  2. +------+
  3. | abcd |
  4. +------+
  5. | test |
  6. | gl |
  7. | zg |
  8. +------+
查看master相关变量
  1. (root@localhost) [mysql]> show status like 'rpl_semi_sync%';
  2. +--------------------------------------------+-------+
  3. | Variable_name | Value |
  4. +--------------------------------------------+-------+
  5. | Rpl_semi_sync_master_clients | 1 |
  6. | Rpl_semi_sync_master_net_avg_wait_time | 0 |
  7. | Rpl_semi_sync_master_net_wait_time | 0 |
  8. | Rpl_semi_sync_master_net_waits | 0 |
  9. | Rpl_semi_sync_master_no_times | 0 |
  10. | Rpl_semi_sync_master_no_tx | 0 |
  11. | Rpl_semi_sync_master_status | ON |
  12. | Rpl_semi_sync_master_timefunc_failures | 0 |
  13. | Rpl_semi_sync_master_tx_avg_wait_time | 417 |
  14. | Rpl_semi_sync_master_tx_wait_time | 834 |
  15. | Rpl_semi_sync_master_tx_waits | 2 |
  16. | Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
  17. | Rpl_semi_sync_master_wait_sessions | 0 |
  18. | Rpl_semi_sync_master_yes_tx | 1 |
主要关注四个参数:
Rpl_semi_sync_master_status ---表示当前master节点是否启用了半同步模式

Rpl_semi_sync_master_no_tx  ---表示当前未成功发送到slave节点的事物数量

Rpl_semi_sync_master_yes_tx ---表示当前已成功发送到slave节点的事物数量

Rpl_semi_sync_master_clients---表示当前处于半同步模式的slave节点数量

5.7的半同步机制变化

一:rpl_semi_sync_master_wait_slave_count参数设置有几个slave接收到了binlog才成功返回客户端请求,缺省是一台,但不可以指定是具体哪台。

二:rpl_semi_sync_master_wait_point 参数,它有两种选择:

AFTER_SYNC(5.7缺省值,5.6中无此选项)
    主库把每一个事务写到二进制日志并且发送给从库,主库在等待从库写到自己的relay-log里的确认信息,在接到确认信息后,主数据库把事务写到存储引擎里并把相应结果反馈给客户端。

AFTER_COMMIT(5.6缺省值)
    主库把每一个事务写到二进制日志并且发送给从库,然后马上就把事务写到存储引擎里;主库在等待从库写到自己的relay-log里的信息确认后,主库把相应结果反馈给客户端。

他们俩个的区别:
AFTER_COMMIT模式的弊端在于,虽然主库一直没有告诉提交事务的客户端事务已经成功(在从库成功确认前)但是实际已经提交了,其它客户端此时已经可以看到事务的结果了。
也就是对于事务提交者自身,的确保证了只要收到成功就一定成功了,但是其它客户端却可能存在发现事务成功了,但最后却没成功,因为数据已经到了存储引擎层。

比如A客户端执行事务将字段id从0修改为1
1.A提交事务到主库
2.主库写binlog
3.主库发送给从库,同时主库提交事务到存储引擎
此时还未收到从库确认,此时A还在等待结果,但是此时另外客户端B已经可以看到字段id为1了。

假如此时主库宕机,如果从库实际收到刚才的事务仅仅是主库未收到确认,那么此时从库的数据还是正确的也是id=1,客户端切换到从库后,都看到id=1
但是如果从库没有实际收到刚才的事务,那么此时从库上id=0,对于客户端A,这个并没有问题,因为A先前提交的事务没有收到任何反馈,所以A需要通过其它方式来确定先前事务是否成功,也就是A可以接受id=0或id=1。
但是对于客户端B来说,已经id=1的变成id=0则很可能是无法接受的

AFTER_SYNC模式则可以解决这个问题,继续上面的例子:
1.A提交事务到主库
2.主库写binlog
3.主库发送给从库
4.主库等待从库确认,此时id=0,没有任何客户端能看到id=1的结果,因为没有提交
5.主库收到从库确认,主库开始提交到存储引擎
6.主库返回结果给客户端

假如第4步时主库宕机,客户端切换到从库,如果从库实际接收到事务,那么此时id=1,如果从库未接收到事务,那么此时id=0,
无论哪种状态,对于所有客户端数据库都是一致,事务都没有丢失,同样客户端A需要自己检查事务状态,因为他没收到反馈,业务上他本身就允许两种可能(提交or回滚)





网页题目:MySQL5.7半同步机制
链接URL:http://scyanting.com/article/pcgccj.html