ithzhang 2020-04-19
MHA目前在MySQL高可用方案中应该也是比较成熟和常见的方案,它由日本人开发出来,在MySQL故障切换过程中,MHA 能做到快速自动切换操作,而且还能最大限度保持数据的一致性,该架构采用 perl 语言编写,可完成秒级别的主库故障切换。
MHA服务有两种角色:MHA Manager(管理节点)和 MHA Node(数据节点)。
MHA 架构中,manager 会定时探测集群中的主库节点,一般为每秒钟探测一次,当主库出现故障后,拉取主库和最新从库的差异日志并应用到该从库上,将该从库提升为新的主库,然后把其他所有的从库重新指向新的主库,由于主库采取 VIP 方式对外提供服务,整个故障转移的过程对应用程序是完全透明的。
为最大程度的保证数据一致性,对于核心业务的数据库参数 sync_binlog、innodb_flush_log_at_trx_commit 均设置为1,每次主库事物提交后都立即写入binlog,并且立即将缓存中的redo日志写到日志文件,并调用操作系统fsync刷新IO缓存。主从同步上采用半同步复制,主库的每个事物需要等待从库返回响应后再对外宣布成功,最大程度的保证数据的一致性。
MHA架构的主要特点如下所示:
?
MHA 架构的工作原理主要步骤如下所示。
?
主机名 | IP地址 | 用途 |
mysqldb01 | 192.168.56.131 | MySQL的主 |
mysqldb02 | 192.168.56.132 | MySQL的从1 |
mysqldb03 | 192.168.56.133 | MySQL的从2 |
mysqldb05 | 192.168.56.135 | MHA manager节点 |
? | 192.168.56.100 | VIP,业务连接使用 |
?
搭建一套一主多从的环境,可以使用传统的方式,也可以使用GTID方式,本文中使用了传统方式,如下内容为各节点my.cnf的配置信息。
MASTER:
[ ~]# more /etc/my.cnf [mysqld] port = 3306 socket = /data/mysql/mysql.sock basedir = /usr/local/mysql datadir = /data/mysql user = mysql symbolic_links = 0 character_set_server = latin1 autocommit = off transaction_isolation = READ-COMMITTED ? server-id = 1 ? ## Master setting log_bin = /data/mysql/logs/binlog log_bin_index = /data/mysql/logs/binlog.index ? ## Slave setting relay_log = /data/mysql/logs/relay-log relay_log_index = /data/mysql/logs/relay-log.index master_info_repository=TABLE relay_log_info_repository=TABLE log_slave_updates = on relay_log_recovery = on relay_log_purge= off ? [mysqld_safe] log_error = /var/log/mysqld.log ? [client] socket = /data/mysql/mysql.sock default_character_set = latin1 prompt="\\\\h [\\d]>" [ ~]# |
?
SLAVE1:
[ ~]# more /etc/my.cnf [mysqld] port = 3306 socket = /data/mysql/mysql.sock basedir = /usr/local/mysql datadir = /data/mysql user = mysql symbolic_links = 0 character_set_server = latin1 autocommit = off transaction_isolation = READ-COMMITTED ? server-id = 2 ? ## Master setting log_bin = /data/mysql/logs/binlog log_bin_index = /data/mysql/logs/binlog.index ? ## Slave setting relay_log = /data/mysql/logs/relay-log relay_log_index = /data/mysql/logs/relay-log.index master_info_repository=TABLE relay_log_info_repository=TABLE log_slave_updates = on relay_log_recovery = on relay_log_purge= off ? [mysqld_safe] log_error = /var/log/mysqld.log ? [client] socket = /data/mysql/mysql.sock default_character_set = latin1 prompt="\\\\h [\\d]>" [ ~]# |
?
SLAVE2:
[ ~]# more /etc/my.cnf [mysqld] port = 3306 socket = /data/mysql/mysql.sock basedir = /usr/local/mysql datadir = /data/mysql user = mysql symbolic_links = 0 character_set_server = latin1 autocommit = off transaction_isolation = READ-COMMITTED ? server-id = 3 ? ## Master setting log_bin = /data/mysql/logs/binlog log_bin_index = /data/mysql/logs/binlog.index ? ? ## Slave setting relay_log = /data/mysql/logs/relay-log relay_log_index = /data/mysql/logs/relay-log.index master_info_repository=TABLE relay_log_info_repository=TABLE log_slave_updates = on relay_log_recovery = on relay_log_purge= off ? [mysqld_safe] log_error = /var/log/mysqld.log ? [client] socket = /data/mysql/mysql.sock default_character_set = latin1 prompt="\\\\h [\\d]>" [ ~]# |
?
在所有MySQL节点授权拥有管理权限的用户可在本地网络中有其他节点上远程访问。 当然, 此时仅需要且只能在 master 节点运行如下SQL语句即可,它会复制到所有的slave节点。
create user ‘mhaadmin‘@‘192.168.56.%‘ identified by ‘mhapass‘; grant all on *.* to ‘mhaadmin‘@‘192.168.56.%‘ ; |
?
MHA集群中的各节点彼此之间均需要基于SSH互信通信,以实现远程控制及数据管理功能。
简单起见,可在Manager节点生成密钥对儿,并设置其可远程连接本地主机后, 将私钥文件及authorized_keys文件复制给余下的所有节点即可。
下面操作在所有节点上进行:
# ssh-keygen -t rsa # ssh-copy-id -i .ssh/id_rsa.pub |
当四台机器都进行了上述操作以后,我们可以在manager机器上看到authorized_keys文件,四台机器的公钥都已经在authorized_keys这个文件中了,接着,我们只需要把这个文件发送至另外三台机器,这四台机器就可以实现SSH无密码互通了。
# scp authorized_keys :~/.ssh/ # scp authorized_keys :~/.ssh/ # scp authorized_keys :~/.ssh/ |
?
四个节点都需安装mha4mysql-node:
#下载MHA-node??https://github.com/yoshinorim/mha4mysql-node/releases #安装依赖,这里遇到的报错大多事因为没有安装依赖环境 yum install -y perl-DBD-MySQL perl-ExtUtils-MakeMaker perl-CPAN #解压 tar zxf mha4mysql-node-0.58.tar.gz #移动到/usr/local/mha4mysql-node-0.58目录下 mv mha4mysql-node-0.58 /usr/local/mha4mysql-node-0.58 #编译 cd /usr/local/mha4mysql-node-0.58 perl Makefile.PL #make并安装 make make install |
?
Manager节点需额外安装mha4mysql-manager:
#下载MHA-manager? https://github.com/yoshinorim/mha4mysql-manager/releases #安装依赖包 yum install –y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager #解压 tar -zxf mha4mysql-manager-0.58.tar.gz #移动目录 mv mha4mysql-manager-0.58 /usr/local/mha4mysql-manager-0.58 # 编译安装 cd /usr/local/mha4mysql-manager-0.58/ perl Makefile.PL make make install |
?
Manager 节点可以为每个application指定一个配置文件,配置文件的路径可以自定义。例如:为这套一主多从的环境创建一个配置文件,命令如下。
# mkdir -p /etc/masterha/app1 # vi /etc/masterha/app1/app1.cnf |
配置管理文件内容如下所示。
[server default] manager_workdir=/etc/masterha/app1 manager_log=/etc/masterha/app1/manager.log #刚才授权的MHA管理用戶名 user=mhaadmin password=mhapass #ssh免密钥登录的帐号名 ssh_user=root #mysql复制帐号,用来在主从机之间同步二进制日志等 repl_user=repuser repl_password=welcome1 #ping间隔,用来检测master是否正常 ping_interval= 1 ? master_ip_failover_script= /etc/masterha/app1/master_ip_failover master_ip_online_change_script= /etc/masterha/app1/master_ip_online_change ? [server1] hostname=192.168.56.131 port=3306 master_binlog_dir=/data/mysql/logs ? [server2] hostname=192.168.56.132 port=3306 master_binlog_dir=/data/mysql/logs candidate_master=1 ? [server3] hostname=192.168.56.133 port=3306 master_binlog_dir=/data/mysql/logs candidate_master=1 |
?
同理:所有的node节点上也执行以上操作。
这两个脚本存放在/etc/masterha/app1目录下。
[ app1]# chmod +x master_ip_failover [ app1]# chmod +x master_ip_online_change |
?
?
?
检测各节点间SSH互信通信配置是否ok,可以在Manager机器上输入下述命令来检测:
# masterha_check_ssh -conf=/etc/masterha/app1/app1.cnf |
执行该命令时,有可能会报错,报错信息如下。
"NI_NUMERICHOST" is not exported by the Socket module "getaddrinfo" is not exported by the Socket module "getnameinfo" is not exported by the Socket module Can‘t continue after import errors at /usr/local/share/perl5/MHA/NodeUtil.pm line 29 ………. |
解决办法:
#打开cpan cpan #查看配置 >o conf #指定阿里云cpan源,国内还是这个比较稳定 >o conf urllist push http://mirrors.aliyun.com/CPAN/ #提交更改 >o conf commit #查看是否修改成功 >o conf urllist #安装相关插件,记得要按yes >install IO::Socket::INET6 #也是相关插件,记得要按yes >install ExtUtils::Constant #还是相关插件,记得要按yes >install YAML #安装上本坑的重点,socket插件 >install Socket #顺便也将坑1的问题也修复一下吧,记得要按yes >install DBD::mysql |
?
检查管理的MySQL复制集群的连接配置参数是否OK,可以在Manager机器上输入下述命令来检测:
# masterha_check_repl -conf=/etc/masterha/app1/app1.cnf |
此命令可能会提示错误:
Sat Apr 18 21:38:59 2020 - [info] Connecting to (192.168.56.132:22).. Can‘t exec "mysqlbinlog": No such file or directory at /usr/local/share/perl5/MHA/BinlogManager.pm line 106. mysqlbinlog version command failed with rc 1:0, please verify PATH, LD_LIBRARY_PATH, and client options |
?
解决办法:
[ etc]# ln -s /usr/local/mysql/bin/mysqlbinlog /usr/local/bin/mysqlbinlog [ etc]# ln -s /usr/local/mysql/bin/mysql /usr/local/bin/mysql [ etc]# |
在所有的MySQL服务器上执行以上语句。
?
那么 MHA 具体是通过什么操作的呢,其实就是一些 perl 脚本,包括manager和node工具包,具体说明如下。
MHA manager端常用工具:
Manager端可能需要使用到的脚本:
在mha4mysql-manager 软件包中包括了这4个脚本的编写示例,编写语言为perl。例如:/usr/local/mha4mysql-manager-0.58/samples/scripts 目录下会有相关脚本,但是提供的这些脚本不完整,需要自己修改:
master_ip_failover //自动切换时vip管理的脚本,不是必须,如果我们使用keepalived的,我们可以自己编写脚本完成对vip的管理,比如监控mysql,如果mysql异常,我们停止keepalived就行,这样vip就会自动漂移
master_ip_online_change //在线切换时vip的管理,不是必须,同样可以可以自行编写简单的shell完成
power_manager //故障发生后关闭主机的脚本,不是必须
send_report //因故障切换后发送报警的脚本,不是必须。
?
也可以自行编写简单的shell完成以上工作。
?
MHA node 端常用工具(这些工具由manager触发,不需人工操作):
?
在manager节点上执行以下命令来启动 MHA:
# nohup masterha_manager -conf=/etc/masterha/app1/app1.cnf &> /etc/masterha/app1/manager.log & |
?
启动成功以后,我们来查看一下master节点的状态:
# masterha_check_status -conf=/etc/masterha/app1/app1.cnf |
?
如果,我们想要停止MHA,则需要使用stop命令:
# masterha_stop -conf=/etc/masterha/app1/app1.cnf |
?
为了防止脑裂发生,推荐生产环境采用脚本的方式来管理虚拟ip,而不是使用keepalived来完成。
手动绑定VIP。需要先在MASTER节点上绑定VIP。
[ ~]# /sbin/ifconfig eth0:1 192.168.56.100/24 [ ~]# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:2a:08:20 brd ff:ff:ff:ff:ff:ff inet 192.168.56.131/24 brd 192.168.56.255 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.56.100/24 brd 192.168.56.255 scope global secondary eth0:1 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe2a:820/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:5e:2e:ac brd ff:ff:ff:ff:ff:ff inet 192.168.1.5/24 brd 192.168.1.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe5e:2eac/64 scope link valid_lft forever preferred_lft forever [ ~]# |
(1)、手动关闭MASTER节点,触发自动FAILOVER。
[ ~]# service mysql stop |
?
[ ~]# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:e2:17:dc brd ff:ff:ff:ff:ff:ff inet 192.168.56.132/24 brd 192.168.56.255 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.56.100/24 brd 192.168.56.255 scope global secondary eth0:1 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fee2:17dc/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:0a:54:96 brd ff:ff:ff:ff:ff:ff inet 192.168.1.6/24 brd 192.168.1.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe0a:5496/64 scope link valid_lft forever preferred_lft forever [ ~]# |
可以看出,VIP已经飘移到SLAVE节点。
(2)、VIP和MASTER会自动切换到SLAVE节点上。但整个MHA环境已经无法自动管理,当以前的MASTER节点恢复后,需要手动将以前的MASTER加入主从恢复,重新构建成一个一主多从的复制环境。
注意:故障转移完成后,manager将会自动停止,此时使用masterha_check_status命令检测将会遇到错误提示,如下所示:
[ ~]# masterha_check_status -conf=/etc/mha_master/mha.cnf mha is stopped(2:NOT_RUNNING). |
需要手动修复整个一主多从环境,才能运行该脚本。
?
处理完毕后,MHA才可以继续工作。
?
手动切换,主要调用masterha_master_switch脚本。
[ bin]# masterha_master_switch --help Usage: # For master failover ? masterha_master_switch --master_state=dead --global_conf=/etc/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf --dead_master_host=host1 ? # For online master switch ? masterha_master_switch --master_state=alive --global_conf=/etc/masterha_default.cnf --conf=/usr/local/masterha/conf/app1.cnf ? See online reference (http://code.google.com/p/mysql-master-ha/wiki/masterha_master_switch) for details. ? [r bin]# |
?
(1)、先停掉MHA监控:
[ bin]# masterha_stop -conf=/etc/masterha/app1/app1.cnf |
?
(2)、其次,进行在线切换操作(模拟在线切换主库操作,原主库192.168.56.131变为slave,192.168.56.133提升为新的主库):
[ bin]# masterha_master_switch --conf=/etc/masterha/app1/app1.cnf --master_state=alive --new_master_host=192.168.56.133 |
?
(3)、在online change的过程中,输出的日志会提示将所有新的SLAVE设置成一个点,并启动SLAVE进程。如下所示。
Sun Apr 19 08:39:25 2020 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST=‘192.168.56.133‘, MASTER_PORT=3306, MASTER_LOG_FILE=‘binlog.000011‘, MASTER_LOG_POS=154, MASTER_USER=‘repuser‘, MASTER_PASSWORD=‘xxx‘; |
?
(4)、手动处理了这些SLAVE后,MHA可以继续工作。