介绍
先了解一下mysql的主从复制是什么回事,我们都知道,mysql主从复制是基于binlog的复制方式,而mysql默认的主从复制方式,其实是异步复制.
主库实际上并不关心从库是否把数据拉完没有,也不关心从库有没有把数据写进硬盘入库,反正数据丢过去,让从库自己慢慢跑,而实际上这也并不影响主库任何使用的情况.
细心的人就会发现,这种情况下,假如主库临时挂了,binlog还没传输完毕,即使是集群也不能保证说这挂了之后的数据一致性,因为你不能排除别人在主库是正常提交的,而从库没有数据的情况.
然后在某个位面的时间上,就有人提出同步复制的概念,意思就是说,只要从库没写入,主库就不返回完成,这个时候即使主库挂了,这也只是一个未完成的事务,从库也不会记录,能保证数据一致性.
看上去,数据一致性是解决了,但是呢,每个事务的延时就增大了,如果是大事务的话,就更惨,这得看网络带宽能不能顶得住,不然延时更低,性能更差.
最后,在mysql5.5之后,半同步就提出来了,意思就是说,每个事务的复制,至少保证一个从库已经收到了binlog,主库才返回事务完成,但不需要理会从库是否写入硬盘.
这样做虽然延时还是有,但是比起完全的同步方式还是好太多,对于数据一致性要求高的情况,牺牲性能来换取一定的价值,是在所难免的.
光看文字难免有些虚,可以看看下面的图片来大致了解一下,
大家留意上面的数字,
第一部,客户端提交sql语句,
第二部,提交给存储引擎解析并处理数据修改,
第三部,事务在主库处理完毕,处于待完成状态,等待最终完成,
第四部,同时提交给各从库,等待完成,
第五部,从库返回状态给主库,标记已完成,
第六部,返回客户端,整个事务已完成.
看上去还是比较不错,主从的数据一致性得到很大的提高,但是延时也不含糊,就是牺牲性能来提高一致性的问题了.
不过我还是得负责任的讲句,在极端的情况下,还是可能会丢一些数据的,所以定期做主从数据校验还是有必要的,例如使用PT工具什么的,至于为什么,这个不仿让大家思考一下,而对于大事务来说,半同步也是比较无力的情况,性能损耗较大.
安装使用
下面来看看如何安装使用半同步,大部分mysql本身并没有预装半同步的组件,需要另外安装,但是一般mysql的包里面会自带so文件,所以只要手动加载一下就可以用了.
先检查下有没有装
mysql> show plugins;
查找是否有semisync字母,有就是装了,没有就是没装.
查找mysql插件目录位置
mysql> show variables like ‘plugin_dir‘; +---------------+------------------------------------+ | Variable_name | Value | +---------------+------------------------------------+ | plugin_dir | /usr/local/mysql/lib/mysql/plugin/ | +---------------+------------------------------------+ 1 row in set (0.00 sec)
查看目录文件是否存在
[[email protected] ~]# ll /usr/local/mysql/lib/mysql/plugin/ 总用量 25328 -rwxr-xr-x 1 root root 16916 3月 4 01:18 adt_null.so -rwxr-xr-x 1 root root 183009 3月 4 01:18 audit_log.so -rwxr-xr-x 1 root root 44095 3月 4 01:18 auth_pam_compat.so -rwxr-xr-x 1 root root 45929 3月 4 01:18 auth_pam.so -rwxr-xr-x 1 root root 27406 3月 4 01:18 auth.so -rwxr-xr-x 1 root root 13607 3月 4 01:18 auth_socket.so -rwxr-xr-x 1 root root 26229 3月 4 01:18 auth_test_plugin.so -rw-r--r-- 1 root root 227 3月 3 21:27 daemon_example.ini drwxr-xr-x 2 root root 4096 3月 4 01:23 debug -rwxr-xr-x 1 root root 4702357 3月 4 01:20 dialog.so -rwxr-xr-x 1 root root 2212305 3月 4 01:18 handlersocket.so -rwxr-xr-x 1 root root 14950125 3月 4 01:22 ha_tokudb.so -rwxr-xr-x 1 root root 834597 3月 4 01:18 innodb_engine.so -rwxr-xr-x 1 root root 39169 3月 4 01:18 libdaemon_example.so -rwxr-xr-x 1 root root 27048 3月 4 01:18 libfnv1a_udf.so -rwxr-xr-x 1 root root 27089 3月 4 01:18 libfnv_udf.so -rwxr-xr-x 1 root root 779519 3月 4 01:18 libmemcached.so -rwxr-xr-x 1 root root 28683 3月 4 01:18 libmurmur_udf.so -rwxr-xr-x 1 root root 17898 3月 4 01:18 mypluglib.so -rwxr-xr-x 1 root root 12224 3月 4 01:18 mysql_no_login.so -rwxr-xr-x 1 root root 18574 3月 4 01:18 qa_auth_client.so -rwxr-xr-x 1 root root 27059 3月 4 01:18 qa_auth_interface.so -rwxr-xr-x 1 root root 13877 3月 4 01:18 qa_auth_server.so -rwxr-xr-x 1 root root 395960 3月 4 01:18 query_response_time.so -rwxr-xr-x 1 root root 56417 3月 4 01:18 scalability_metrics.so -rwxr-xr-x 1 root root 537609 3月 4 01:18 semisync_master.so -rwxr-xr-x 1 root root 289069 3月 4 01:18 semisync_slave.so -rwxr-xr-x 1 root root 357058 3月 4 01:18 tokudb_backup.so -rwxr-xr-x 1 root root 188402 3月 4 01:18 validate_password.so
看到下面两个,就是半同步的组件了,一个是主库组件,一个是从库组件,你可以两个都装上或者只装一个.
semisync_master.so semisync_slave.so
下面开始正式安装:
在主库上执行
mysql> install plugin rpl_semi_sync_master soname ‘semisync_master.so‘; mysql> show plugins; 看到下面这个就证明成功了 rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL
然后在从库执行
mysql> install plugin rpl_semi_sync_slave soname ‘semisync_slave.so‘; mysql> show plugins; 看到下面这个就证明成功了 rpl_semi_sync_slave | ACTIVE | REPLICATION | semisync_slave.so | GPL
安装完了,就开始准备启动了,
主库很简单,只要设置一下半同步启动就可以了.
mysql> set global rpl_semi_sync_master_enabled = on;
当然,你也可以写到配置文件,不过写到配置文件要重启才生效,而且还要重新加载组件,所以这就没意思了.
然后到从库,slave要重启动IO线程来生效,否则还是异步的方式复制数据。
mysql> set global rpl_semi_sync_slave_enabled = on; mysql> stop slave IO_THREAD; mysql> start slave IO_THREAD;
同样你也能写到配置文件,我就不多说了,反正这就启动完毕了.
下面来验证一下是否成功,以下是主库的信息,因为从库很多信息是没有的.
mysql> show status like ‘%Rpl_semi_sync%‘; +--------------------------------------------+---------+ | Variable_name | Value | +--------------------------------------------+---------+ | Rpl_semi_sync_master_clients | 1 | | Rpl_semi_sync_master_net_avg_wait_time | 746 | | Rpl_semi_sync_master_net_wait_time | 3788497 | | Rpl_semi_sync_master_net_waits | 5077 | | 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 | 614 | | Rpl_semi_sync_master_tx_wait_time | 2797020 | | Rpl_semi_sync_master_tx_waits | 4552 | | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 5077 | | Rpl_semi_sync_slave_status | OFF | +--------------------------------------------+---------+ 15 rows in set (0.00 sec)
解释几个重要的值。
Rpl_semi_sync_master_status是否启用了半同步。
Rpl_semi_sync_master_clients半同步模式下Slave一共有多少个。
Rpl_semi_sync_master_no_tx往slave发送失败的事务数量。
Rpl_semi_sync_master_yes_tx往slave发送成功的事务数量。
看完上面的解析,大概你也知道我这个状态是正常的了.其他延时类别的,大家得看实际情况.
来看看我们能设置些什么关于半同步的参数
mysql> show variables like ‘%Rpl%‘; +------------------------------------+----------+ | 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 | | rpl_semi_sync_slave_enabled | OFF | | rpl_semi_sync_slave_trace_level | 32 | | rpl_stop_slave_timeout | 31536000 | +------------------------------------+----------+ 7 rows in set (0.00 sec)
也来看看解析:
rpl_semi_sync_master_timeout Master等待slave响应的时间,单位是毫秒,默认值是10秒,超过这个时间,slave无响应,环境架构将自动转换为异步复制
rpl_semi_sync_master_trace_level 监控等级,一共4个等级(1,16,32,64)。
rpl_semi_sync_master_wait_no_slave 是否允许master 每个事物提交后都要等待slave的receipt信号。默认为on ,每一个事务都会等待,如果slave当掉后,当slave追赶上master的日志时,可以自动的切换为半同步方式,如果为off,则slave追赶上后,也不会采用半同步的方式复制了,需要手工配置。
rpl_stop_slave_timeout 控制stop slave 的执行时间,在重放一个大的事务的时候,突然执行stop slave ,命令 stop slave会执行很久,这个时候可能产生死锁或阻塞,严重影响性能,mysql 5.6可以通过rpl_stop_slave_timeout参数控制stop slave 的执行时间
毫无疑问,这些参数都能通过配置文件或直接set来更改,只要你觉得这个适合你的需求,例如一般我们会把响应时间设成1秒.
最后,我们来看看同样的命令在从库会有些什么信息
mysql> show status like ‘%Rpl_semi_sync%‘; +--------------------------------------------+-------+ | 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 | ON | +--------------------------------------------+-------+ 15 rows in set (0.00 sec)
也正如我刚才说的,很多信息基本上没有,只有最后一行是不一样的,也只是证明从库正常连接中.
再看看这个
mysql> show variables like ‘%Rpl%‘; +------------------------------------+----------+ | 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 | | rpl_semi_sync_slave_enabled | ON | | rpl_semi_sync_slave_trace_level | 32 | | rpl_stop_slave_timeout | 31536000 | +------------------------------------+----------+ 7 rows in set (0.00 sec)
也是差不多,纯粹就是状态不一样.