之前一直没有对semi sync做太多的关注,原因是线上的生产环境使用的非常少,最近需要提升semisync的生产环境优先级,以适应数据保护非常严格的场景,借此机会了解一下semisync,顺便过了一下大部分代码,以帮助后续的性能优化工作,以下分析基于代码MySQL5.6.13
如何配置
semisync的配置非常简单,采用MySQL Plugin的方式,在主库和备库上分别安装不同的插件,当然你也可以主库备库全部标准安装上,使用参数来控制sesmisync;
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
正常情况下,这两个PLUGIN都应该被标准安装,谁知道哪天备库会不会被切换成主库呢。
安装完PLUGIN后,我们可以根据拓扑结构来定义主库和备库的配置,主要包括以下几个配置项;
1.rpl_semi_sync_master_enabled
—控制主库上是否开启semisync, 打开或关闭,立刻生效
2.rpl_semi_sync_slave_enabled
—控制备库是否开启semisync,
当主库打开semisync时,则必须至少要有一个链接的备库是打开semisync的,否则主库线程每次都会去等待,直至超时;因此如果想关闭semisync必须要先关闭主库配置,再关闭备库配置
3.rpl_semi_sync_master_timeout
—控制主库上客户端的等待时间,当超过这么长时间等待后,客户端返回,同步复制退化成原生的异步复制
单位为毫秒,默认值为10000,即10秒
默认打开,表示当备库起来后,并跟上主库时,自动切换到同步模式,如果关闭,即使备库起来并跟上了,也不会启用半同步;
– 输出监控信息的级别,详细点击见文档,不同的级别,可能输出更详细的信息,用于DEBUG
运行状态变量也比较丰富,不细说了,网上介绍的很多,官方文档也很详细
root@(none) 02:58:27>show 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 | OFF |
| 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 |
| Rpl_semi_sync_slave_status | OFF |
+--------------------------------------------+-------+
15 rows in set (0.00 sec)
源代码实现
采用plugin +代码HOOK的方式实现,通过HOOK来回调在plugin中定义的函数
例如:
RUN_HOOK(transaction, after_commit, (head, all));
RUN_HOOK的定义在rpl_hander.h中:
#define RUN_HOOK(group, hook, args) \
(group ##_delegate->is_empty() ? \
0 : group ##_delegate->hook args)
因此上例被转化成
transaction_delegate->after_commit(head, all);
更具体的回调接口函数在sql/rpl_hander.cc文件中定义
有四类_delegate对象
binlog_storage_delegate、transaction_delegate、binlog_transmit_delegate、binlog_relay_io_delegate
主库
在主库semisync加载或初始化时,调用函数semi_sync_master_plugin_init,为transaction_delegate,binlog_transmit_delegate和binlog_transmit_delegate增加了observer,分别对应该plugin的变量为trans_observer,storage_observer,transmit_observer,这三个obeserver定义了各自的函数接口,如下:
Trans_observer trans_observer = {
sizeof(Trans_observer), // len
repl_semi_report_commit, // after_commit
repl_semi_report_rollback, // after_rollback
};
Binlog_storage_observer storage_observer = {
sizeof(Binlog_storage_observer), // len
repl_semi_report_binlog_update, // report_update
};
Binlog_transmit_observer transmit_observer = {
sizeof(Binlog_transmi