MHA(Master High Availability)目前在 MySQL 高可用方面是一个相对成熟的解决方案是一套优秀的作为 MySQL 高可用性环境下故障切换和主从提升的高可用软件。
在 MySQL 故障切换过程中,MHA 能做到在 0~30 秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA 能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
该软件由两部分组成:MHA Manager(管理节点)和 MHA Node(数据节点)。MHA Manager 可以单独部署在一台独立的机器上管理多个 master-slave 集群,也可以部署在一台 slave 节点上。MHA Node 运行在每台 MySQL 服务器上,MHA Manager 会定时探测集群中的 master 节点,当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master,然后将所有其他的 slave 重新指向新的 master。整个故障转移过程对应用程序完全透明。
在 MHA 自动故障切换过程中,MHA 试图从宕机的主服务器上保存二进制日志,最大程度的保证数据的不丢失,但这并不总是可行的。例如,如果主服务器硬件故障或无法通过 ssh 访问,MHA 没法保存二进制日志,只进行故障转移而丢失了最新的数据。使用 MySQL 5.5 的半同步复制,可以大大降低数据丢失的风险。MHA 可以与半同步复制结合起来。如果只有一个 slave 已经收到了最新的二进制日志,MHA 可以将最新的二进制日志应用于其他所有的 slave 服务器上,因此可以保证所有节点的数据一致性。
注意:从MySQL5.5开始,MySQL以插件的形式支持半同步复制。
同步概念
如何理解半同步呢?首先我们来看看异步,全同步的概念:
异步复制(Asynchronous replication) MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。
全同步复制(Fully synchronous replication) 指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
半同步复制(Semisynchronous replication) 介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。
总结:异步与半同步异同 默认情况下MySQL的复制是异步的,Master上所有的更新操作写入Binlog之后并不确保所有的更新都被复制到Slave之上。异步操作虽然效率高,但是在Master/Slave出现问题的时候,存在很高数据不同步的风险,甚至可能丢失数据。 MySQL5.5引入半同步复制功能的目的是为了保证在master出问题的时候,至少有一台Slave的数据是完整的。在超时的情况下也可以临时转入异步复制,保障业务的正常使用,直到一台salve追赶上之后,继续切换到半同步模式。
工作原理
相较于其它HA软件,MHA的目的在于维持MySQL Replication中Master库的高可用性,其最大特点是可以修复多个Slave之间的差异日志,最终使所有Slave保持数据一致,然后从中选择一个充当新的Master,并将其它Slave指向它。
- 从宕机崩溃的master保存二进制日志事件(binlogevents)。
- 识别含有最新更新的slave。
- 应用差异的中继日志(relay log)到其它slave。
- 应用从master保存的二进制日志事件(binlogevents)。
- 提升一个slave为新master。
- 使其它的slave连接新的master进行复制。
目前 MHA 主要支持一主多从的架构,要搭建 MHA, 要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当 master,一台充当备用 master,另外一台充当从库,因为至少需要三台服务器,出于机器成本的考虑,淘宝也在该基础上进行了改造,目前淘宝 TMHA 已经支持一主一从。
环境拓扑
其中master1对外提供写服务,备选master(实际为slave,主机名master2)提供读服务,slave也提供相关的读服务,一旦master1宕机,将会把备选master提升为新的master,slave指向新的master,manager作为管理服务器。生产环境中,是有很多从,从的操作都是一样的,这里以两台slave为例,而备选master也作为slave。
环境准备
1、 在配置好IP地址后检查selinux,iptables设置,关闭 selinux ,iptables 服务以便后期主从同步不出错 注:时间要同步 。
2、 在四台机器都配置epel源
[root@manager ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
3、建立ssh无交互登录环境
manager
下面四台主机都需要执行互信,通过for循环把公钥传出去。(互信时直接按回车即可,但是传出去需要允许(yes),然后输入对端密码)
1. [root@manager ~]# ssh-keygen -t rsa 2. Generating public/private rsa key pair. 3. Enter file in which to save the key (/root/.ssh/id_rsa): 4. Created directory '/root/.ssh'. 5. Enter passphrase (empty for no passphrase): 6. Enter same passphrase again: 7. Your identification has been saved in /root/.ssh/id_rsa. 8. Your public key has been saved in /root/.ssh/id_rsa.pub. 9. The key fingerprint is: 10. SHA256:8zzNm0tUTQ9bw/E9GQ6+1BbJIPOn5iWPsms6suwmFUU root@manager 11. The key's randomart image is: 12. +---[RSA 2048]----+ 13. | .E o o===| 14. | . = +XO| 15. | . +oB=| 16. | . ..= .| 17. | S .= . | 18. | . + +o = | 19. | . +.+o . | 20. | ..o . +oo | 21. | ++o.+o=. | 22. +----[SHA256]-----+ 23. [root@manager ~]# for i in 20 30 40 50;do ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.8.$i;done
master1
1. [root@master1 ~]# ssh-keygen -t rsa 2. Generating public/private rsa key pair. 3. Enter file in which to save the key (/root/.ssh/id_rsa): 4. Enter passphrase (empty for no passphrase): 5. Enter same passphrase again: 6. Your identification has been saved in /root/.ssh/id_rsa. 7. Your public key has been saved in /root/.ssh/id_rsa.pub. 8. The key fingerprint is: 9. SHA256:cBhASzDVEouISwajm3/j3L3XjLvwYzQzEvkTi2800+k root@master1 10. The key's randomart image is: 11. +---[RSA 2048]----+ 12. |o o+*+. | 13. |+o +.o.o | 14. |+o. o.o .. | 15. |o+ oo . | 16. |+ S+ + . | 17. | . o % o | 18. | . o .= % | 19. | + o . oB E | 20. | o . o=++ | 21. +----[SHA256]-----+ 22. [root@master1 ~]# for i in 20 30 40 50;do ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.8.$i;done
master2
1. [root@master2 ~]# ssh-keygen -t rsa 2. Generating public/private rsa key pair. 3. Enter file in which to save the key (/root/.ssh/id_rsa): 4. Enter passphrase (empty for no passphrase): 5. Enter same passphrase again: 6. Your identification has been saved in /root/.ssh/id_rsa. 7. Your public key has been saved in /root/.ssh/id_rsa.pub. 8. The key fingerprint is: 9. SHA256:MHKw5P1AEBshLUAPUnIKQ/wPtXYAxfMOU/cNErvjZLo root@master2 10. The key's randomart image is: 11. +---[RSA 2048]----+ 12. |X*+o@=. .. | 13. |o*++.% . o.. | 14. |. .o* % ..o o | 15. | o B B .. . | 16. | + = S= | 17. | . .= . | 18. | . . | 19. | . | 20. | E | 21. +----[SHA256]-----+ 22. [root@master2 ~]# for i in 20 30 40 50;do ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.8.$i;done
slave
1. [root@slave ~]# ssh-keygen -t rsa 2. Generating public/private rsa key pair. 3. Enter file in which to save the key (/root/.ssh/id_rsa): 4. Enter passphrase (empty for no passphrase): 5. Enter same passphrase again: 6. Your identification has been saved in /root/.ssh/id_rsa. 7. Your public key has been saved in /root/.ssh/id_rsa.pub. 8. The key fingerprint is: 9. SHA256:3RuS1syMJTLHKzqrHLph3xRDuCh7xDU05i6zqfqnFQM root@slave 10. The key's randomart image is: 11. +---[RSA 2048]----+ 12. | + | 13. | + o . | 14. | E = . o + . | 15. | . = + = % | 16. |. * = o S B B | 17. | + = o + o . o | 18. |. * o + . | 19. | + *.+ o | 20. |+.=++.o | 21. +----[SHA256]-----+ 22. [root@slave ~]# for i in 20 30 40 50;do ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.8.$i;done
测试ssh交互,远程查看各主机名称
1. [root@manager ~]# for i in 20 30 40 50 ;do ssh 192.168.8.$i hostname;done 2. manager 3. master1 4. master2 5. slave
4、配置hosts环境
1. [root@manager ~]# vim /etc/hosts 2. #插入四行数据 3. 192.168.8.20 manager 4. 192.168.8.30 master1 5. 192.168.8.40 master2 6. 192.168.8.50 slave 7. [root@manager ~]# for i in 20 30 40 50;do scp /etc/hosts root@192.168.8.$i:/etc/;done 8. hosts 100% 240 201.6KB/s 00:00 9. hosts 100% 240 151.9KB/s 00:00 10. hosts 100% 240 160.9KB/s 00:00 11. hosts 100% 240 105.1KB/s 00:00
配置半同步复制
为了尽可能的减少主库硬件损坏宕机造成的数据丢失,因此在配置MHA的同时建议配置成MySQL的半同步复制。 注:mysql半同步插件是由谷歌提供,具体位置/usr/local/mysql/lib/plugin/下,一个是master用的semisync_master.so,一个是slave用的semisync_slave.so。 如果不清楚Plugin的目录,用下面命令查找。
1. mysql> 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)
1、分别在主从节点上安装相关的插件(master, Candicate master,slave) 在MySQL上安装插件需要数据库支持动态载入。检查是否支持,用下面命令检测:
1. mysql> show variables like '%have_dynamic%'; 2. +----------------------+-------+ 3. | Variable_name | Value | 4. +----------------------+-------+ 5. | have_dynamic_loading | YES | 6. +----------------------+-------+ 7. 1 row in set (0.00 sec)
注意:在所有mysql数据库服务器,安装半同步插件(semisync_master.so,semisync_slave.so)
1. mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; 2. Query OK, 0 rows affected (0.01 sec) 3. 4. mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; 5. Query OK, 0 rows affected (0.01 sec)
使用下面命令查看是否成功
1. mysql> show plugins; 2. 或者 3. mysql> select * from information_schema.plugins;
查看半同步信息
1. mysql> 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. | rpl_semi_sync_slave_enabled | OFF | 12. | rpl_semi_sync_slave_trace_level | 32 | 13. +-------------------------------------------+------------+ 14. 8 rows in set (0.01 sec)
上面可以看到半同复制插件已经安装,只是还没有启用,所以是off 。
2、修改my.cnf文件,配置主从同步
若主MYSQL服务器已经存在,只是后期才搭建从MYSQL服务器,在置配数据同步前应先将主MYSQL服务器的要同步的数据库拷贝到从MYSQL服务器上(如先在主MYSQL上备份数据库,再用备份在从MYSQL服务器上恢复)
master1
1. [root@master1 ~]# vim /etc/my.cnf 2. server-id = 1 3. log-bin=mysql-bin 4. binlog_format=mixed 5. log-bin-index=mysql-bin.index 6. rpl_semi_sync_master_enabled=1 7. rpl_semi_sync_master_timeout=1000 8. rpl_semi_sync_slave_enabled=1 9. relay_log_purge=0 10. relay-log = relay-bin 11. relay-log-index = slave-relay-bin.index 12. [root@master1 ~]# systemctl restart mysqld
注:rpl_semi_sync_master_enabled=1 1表是启用,0表示关闭 rpl_semi_sync_master_timeout=10000:毫秒单位 ,该参数主服务器等待确认消息10秒后,不再等待,变为异步方式。
master2
1. [root@master2 ~]# vim /etc/my.cnf 2. server-id = 2 3. log-bin=mysql-bin 4. binlog_format=mixed 5. log-bin-index=mysql-bin.index 6. relay_log_purge=0 7. relay-log = relay-bin 8. relay-log-index = slave-relay-bin.index 9. rpl_semi_sync_master_enabled=1 10. rpl_semi_sync_master_timeout=10000 11. rpl_semi_sync_slave_enabled=1 12. [root@master2 ~]# systemctl restart mysqld
注:relay_log_purge=0,禁止 SQL 线程在执行完一个 relay log 后自动将其删除,对于MHA场景下,对于某些滞后从库的恢复依赖于其他从库的relay log,因此采取禁用自动删除功能.
slave
1. [root@slave ~]# vim /etc/my.cnf 2. server-id = 3 3. log-bin = mysql-bin 4. relay-log = relay-bin 5. relay-log-index = slave-relay-bin.index 6. read_only = 1 7. rpl_semi_sync_slave_enabled=1 8. [root@slave ~]# systemctl restart mysqld
查看状态
查看三台主机的半同步信息
1. mysql> show variables like '%rpl_semi_sync%'; 2. +-------------------------------------------+------------+ 3. | Variable_name | Value | 4. +-------------------------------------------+------------+ 5. | rpl_semi_sync_master_enabled | ON | 6. | rpl_semi_sync_master_timeout | 1000 | 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. | rpl_semi_sync_slave_enabled | ON | 12. | rpl_semi_sync_slave_trace_level | 32 | 13. +-------------------------------------------+------------+ 14. 8 rows in set (0.01 sec)
查看三台主机的半同步状态
1. mysql> show status like '%rpl_semi_sync%'; 2. +--------------------------------------------+-------+ 3. | Variable_name | Value | 4. +--------------------------------------------+-------+ 5. | Rpl_semi_sync_master_clients | 0 | 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 | 0 | 14. | Rpl_semi_sync_master_tx_wait_time | 0 | 15. | Rpl_semi_sync_master_tx_waits | 0 | 16. | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | 17. | Rpl_semi_sync_master_wait_sessions | 0 | 18. | Rpl_semi_sync_master_yes_tx | 0 | 19. | Rpl_semi_sync_slave_status | OFF | 20. +--------------------------------------------+-------+ 21. 15 rows in set (0.01 sec)
有几个状态参数值得关注:
rpl_semi_sync_master_status :显示主服务是异步复制模式还是半同步复制模式
rpl_semi_sync_master_clients :显示有多少个从服务器配置为半同步复制模式
rpl_semi_sync_master_yes_tx :显示从服务器确认成功提交的数量
rpl_semi_sync_master_no_tx :显示从服务器确认不成功提交的数量
rpl_semi_sync_master_tx_avg_wait_time :事务因开启 semi_sync ,平均需要额外等待的时间
rpl_semi_sync_master_net_avg_wait_time :事务进入等待队列后,到网络平均等待时间