MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。 MHA里有两个角色一个是MHA Node(数据节点)另一个是MHA Manager(管理节点)。 MHA Manager可以单独部署在一台独立的机器上管理多个master-slave集群,也可以部署在一台slave节点上。MHA Node运行在每台MySQL服务器上,MHA Manager会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master,然后将所有其他的slave重新指向新的master。整个故障转移过程对应用程序完全透明。
MHA工作架构示意图如下:
在MHA架构中,可以采用半同步复制的方式,来最大限度的保证数据的一致性,MySQL的主从复制中,默认是采用异步来做主从复制的,但是异步有些弊端,下面是对异步、半同步的一个简单介绍:
- 异步与半同步:默认情况下MySQL的复制是异步的,Master上所有的更新操作写入Binlog之后并不确保所有的更新都被复制到Slave之上。异步操作虽然效率高,但是在Master/Slave出现问题的时候,存在很高数据不同步的风险,甚至可能丢失数据。 MySQL5.5引入半同步复制功能的目的是为了保证在master出问题的时候,至少有一台Slave的数据是完整的。在超时的情况下也可以临时转入异步复制,保障业务的正常使用,直到一台salve追赶上之后,继续切换到半同步模式。
MHA相比较于其他HA软件,MHA的目的在于维持MySQL replication中master库的高可用性,其最大的特点是可以修复多个slave之间的差异日志,最终使所有slave保持数据一致,然后从中选择一个充当新的master,并将其他slave指向它。
大概流程如下:
1、从宕机的master保存二进制日志事件;
2、识别含有最新更新的slave;
3、应用差异的中继日志(relay log)到其他slave;
4、应用从master保存的二进制日志事件;
5、提升一个slave为新master;
6、使其他的slave连接到新的master进行复制。
目前MHA主要支持一主多从的架构,要搭建MHA,一般MySQL集群中最少有三台数据库节点,一主二从,即:一台充当master,一台充当备用master,另外一台充当slave。
1、MHA切换不依赖实例使用存储引擎和BINLOG格式;
2、MHA不会增加MySQL服务器性能开销,除MHA管理节点外无需增加额外服务器;
3、在MySQL服务器上部署MHA数据节点不会影响当前实例运行;
4、MHA实现自动故障切换,也可以手动触发在线切换;
5、MHA可以实现秒级的故障切换;
6、MHA可以将任意slave提升master,也可以在切换时指定master候选节点;
7、MHA提供扩展接口,允许在MHA切换过程中的特定时间点执行用户自定义脚本。
1、只支持BINLOG V4版本,要求MySQL 5.0或更高版本。
2、候选master节点必须开启log-bin参数,如果所有从节点都为开启,则不进行故障转移。
3、在MHA 0.52版本前不支持多master模式
4、MHA默认不支持多级主从复制,通过修改配置文件和设置multi_tier_slave参数
OS | IP地址 | 主机名&角色 | 类型 |
---|---|---|---|
Centos 7.5 | 192.168.20.2 | master | 主master(写操作) |
Centos 7.5 | 192.168.20.3 | slave1 | 从(备主)mysql(读操作) |
Centos 7.5 | 192.168.20.4 | slave2 | 从mysql(读操作) |
Centos 7.5 | 192.168.20.5 | manager | 管理节点 |
在上述环境中,master对外提供写服务,slave提供读操作,一旦master宕机,将会把其中一台slave(我这里将指定的是备主)提升为新的master,slave同时也指向新的master,manager作为管理服务器。
以下操作在其中一个节点执行即可。
#编写host文件
[root@master ~]# cat >> /etc/hosts << EOF
> 192.168.20.2 master
> 192.168.20.3 slave1
> 192.168.20.4 slave2
> 192.168.20.5 manager
> EOF
> #将编写好的hosts文件分发到其他节点
[root@master ~]# for i in master slave1 slave2 manager;do scp /etc/hosts $i:/etc/;done
注:集群中的所有主机都需要保证互相可以免密登录。
将以下两条命令在所有节点上执行一次,即可完成主机间的免密登录
# 创建密钥对
[root@master ~]# ssh-keygen -t rsa
#将公钥分发到其他节点
[root@master ~]# for i in master slave1 slave2 manager;do ssh-copy-id $i;done
当所有节点都执行上面的两条命令,即可使用以下命令来验证,免密登录是否成功:
#如果每台主机上执行以下指令不用输入密码就可以获取所有主机的主机名,说明免密登录配置无误
[root@master ~]# for i in master slave1 slave2 manager;do ssh $i hostname;done
master
slave1
slave2
manager
注:以下命令需要在所有节点执行。
#配置阿里的epel源(为加快安装速度),若非国内环境,执行yum -y install epel-release进行配置即可
[root@master ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@master ~]# yum makecache #建立元数据缓存
# 安装所需依赖
[root@master ~]# yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-ParallelForkManager perl-Config-IniFiles ncftp perl-Params-Validate perl-CPAN perl-TestMock-LWP.noarch perl-LWP-Authen-Negotiate.noarch perl-devel perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker
注:接下来所有操作,如果没有特别说明,是需要在所有数据库服务器上进行执行的。
mysql> show variables like '%plugin_dir%'; #查找插件所在目录(每台DB服务器可能不一样)
+---------------+------------------------------+
| Variable_name | Value |
+---------------+------------------------------+
| plugin_dir | /usr/local/mysql/lib/plugin/ |
+---------------+------------------------------+
1 row in set (0.01 sec)
mysql> show variables like '%have_dynamic%'; #检查是否支持动态检测
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| have_dynamic_loading | YES |
+----------------------+-------+
1 row in set (0.01 sec)
[root@master ~]# ls /usr/local/mysql/lib/plugin/ | egrep 'master|slave'
#确定插件的目录下有以下两个文件(默认安装数据库后就有这些的)
semisync_master.so
semisync_slave.so
# semisync_master.so和semisync_slave.so为上面查询到的插件名字
mysql> install plugin rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> show plugins;
# 或者
mysql> select * from information_schema.plugins;
show plugins执行后返回如下结果,表示没有问题:
mysql> show variables like '%rpl_semi_sync%';
+-------------------------------------------+------------+
| 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_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
| rpl_semi_sync_slave_enabled | OFF |
| rpl_semi_sync_slave_trace_level | 32 |
+-------------------------------------------+------------+
可以看到半同步插件还是未启用的off状态,所以需要修改my.cnf配置文件,如下:
master主机完整配置文件如下:
[root@master ~]# cat /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=1
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
log-bin=mysql-bin
binlog_format=mixed
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000
rpl_semi_sync_slave_enabled=1
relay_log_purge=0
relay-log = relay-bin
relay-log-index = slave-relay-bin.index
注:
- rpl_semi_sync_master_enabled=1:1表是启用,0表示关闭
- rpl_semi_sync_master_timeout=1000:毫秒单位 ,该参数主服务器等待确认消息10秒后,不再等待,变为异步方式。
slave1主机完整配置文件如下:
[root@slave1 ~]# cat /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=2
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
log-bin=mysql-bin
binlog_format=mixed
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000
rpl_semi_sync_slave_enabled=1
relay_log_purge=0
relay-log = relay-bin
relay-log-index = slave-relay-bin.index
slave2主机的完整配置文件如下:
[root@slave2 ~]# cat /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=3
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
log-bin = mysql-bin
relay-log = relay-bin
relay-log-index = slave-relay-bin.index
read_only = 1
rpl_semi_sync_slave_enabled=1
#由于slave2只是用来做一个slave主机,所以无需开启master的半同步
在配置主从复制中,由于主和备主这两台主机上设置了参数relay_log_purge=0(表示不自动清除中继日志),所以slave节点需要定期删除中继日志,建议每个slave节点删除中继日志的时间错开。
crontab -e
0 5 * * * /usr/local/bin/purge_relay_logs - -user=root --password=pwd123 --port=3306 --disable_relay_log_purge >> /var/log/purge_relay.log 2>&1
更改配置文件后,需要执行以下命令进行重启MySQL。
[root@master ~]# systemctl restart mysqld
查看半同步状态,确认已开启:
mysql> show variables like '%rpl_semi_sync%'; #查看半同步是否开启
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON | #这个值要为ON
| rpl_semi_sync_master_timeout | 1000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
| rpl_semi_sync_slave_enabled | ON | #这个值也要为ON。
| rpl_semi_sync_slave_trace_level | 32 |
+-------------------------------------------+------------+
8 rows in set (0.00 sec)
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 | ON |
| 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)
#关于上个命令查看到的信息,有几个状态值得关注,将在下面写下来。
- rpl_semi_sync_master_status :显示主服务是异步复制模式还是半同步复制模式,ON为半同步;
- 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 :事务进入等待队列后,到网络平均等待时间
1)master主机操作如下:
# 创建用于同步的用户
mysql> grant replication slave on *.* to mharep@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (1.00 sec)
# 创建用户mha的manager监控的用户
mysql> grant all on *.* to manager@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.00 sec)
# 查看master二进制相关的信息
mysql> show master status\G
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 744
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
2)slave1主机操作如下:
# 创建用于同步的用户
mysql> grant replication slave on *.* to mharep@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (1.00 sec)
# 创建用户mha的manager监控的用户
mysql> grant all on *.* to manager@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.00 sec)
3)slave2主机操作如下:
由于slave2无需做备主,所以不用创建用于同步数据的账户
#创建manager监控账号
mysql> grant all on *.* to manager@'192.168.20.%' identified by '123.com';
Query OK, 0 rows affected, 1 warning (0.00 sec)
以下操作需要在slave1和slave2主机上分别执行一次,以便同步master主机的数据。
#指定master主机的相关信息
mysql> change master to
-> master_host='192.168.20.2',
-> master_port=3306,
-> master_user='mharep',
-> master_password='123.com',
-> master_log_file = 'mysql-bin.000001', #这是在master主机上查看到的二进制日志名
-> master_log_pos=744; #同上,这是查看到的二进制日志的position
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave; #启动slave
Query OK, 0 rows affected (0.00 sec)
最后查看slave主机的状态:
在master主机上查看半同步相关信息,会发现同步的client已经变成了2,如下:
注:需要MHA-node需要在所有节点安装(包括manager主机节点)
#下载包
[root@master src]# wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58.tar.gz
#安装
[root@master src]# tar zxf mha4mysql-node-0.58.tar.gz
[root@master src]# cd mha4mysql-node-0.58/
[root@master mha4mysql-node-0.58]# perl Makefile.PL
[root@master mha4mysql-node-0.58]# make && make install
注:接下来的所有操作,如果没有特别标注,则只需要在manager主机节点上执行即可。
#下载包
[root@manager src]# wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58.tar.gz
#安装
[root@manager src]# tar zxf mha4mysql-manager-0.58.tar.gz
[root@manager src]# cd mha4mysql-manager-0.58/
[root@manager mha4mysql-manager-0.58]# perl Makefile.PL
[root@manager mha4mysql-manager-0.58]# make && make install
[root@manager mha4mysql-manager-0.58]# mkdir /etc/masterha
[root@manager mha4mysql-manager-0.58]# mkdir -p /masterha/app1
[root@manager mha4mysql-manager-0.58]# mkdir /scripts
[root@manager mha4mysql-manager-0.58]# pwd
/usr/src/mha4mysql-manager-0.58 #确定当前所在目录
[root@manager mha4mysql-manager-0.58]# cp samples/conf/* /etc/masterha/
[root@manager mha4mysql-manager-0.58]# cp samples/scripts/* /scripts/
注:manager共有两个主要的配置文件,一个是通用默认的,一个是单独的。需要将默认通用的配置文件的内容清空,如下:
#清空默认的配置文件
[root@manager masterha]# > /etc/masterha/masterha_default.cnf
然后修改单独的配置文件:
[root@manager ~]# cat /etc/masterha/app1.cnf #修改如下:
[server default]
manager_workdir=/masterha/app1 #指定工作目录
manager_log=/masterha/app1/manager.log #指定日志文件
user=manager #指定manager管理数据库节点所使用的用户名
password=123.com #对应的是上面用户的密码
ssh_user=root #指定配置了ssh免密登录的系统用户
repl_user=mharep #指定用于同步数据的用户名
repl_password=123.com #对应的是上面同步用户的 密码
ping_interval=1 #设置监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应时自动进行切换
[server1]
hostname=192.168.20.2
port=3306
master_binlog_dir=/usr/local/mysql/data #指定master保存二进制日志的路径,以便MHA可以找到master的日志
candidate_master=1 #设置为候选master,设置该参数后,发生主从切换以后将会将此库提升为主库
[server2]
hostname=192.168.20.3
port=3306
master_binlog_dir=/usr/local/mysql/data
candidate_master=1 #设置为候选master
[server3]
hostname=192.168.20.4
port=3306
master_binlog_dir=/usr/local/mysql/data
no_master=1 #设置的不为备选主库
完整无注释的配置文件如下:
[root@manager ~]# cat /etc/masterha/app1.cnf
[server default]
manager_workdir=/masterha/app1
manager_log=/masterha/app1/manager.log
user=manager
password=123.com
ssh_user=root
repl_user=mharep
repl_password=123.com
ping_interval=1
[server1]
hostname=192.168.20.2
port=3306
master_binlog_dir=/usr/local/mysql/data
candidate_master=1
[server2]
hostname=192.168.20.3
port=3306
master_binlog_dir=/usr/local/mysql/data
candidate_master=1
[server3]
hostname=192.168.20.4
port=3306
master_binlog_dir=/usr/local/mysql/data
no_master=1
验证SSH有效性:
验证集群复制的有效性(MySQL必须都启动),如下:
[root@manager masterha]# masterha_check_repl --global_conf=/etc/masterha/masterha_default.cnf --conf=/etc/masterha/app1.cnf
执行上述命令可能会报错如下:
这是因为没有在mysql节点上找到mysqlbinlog这个命令,只需要在所有MySQL主机节点上执行以下命令创建软连接即可,如下:
#注:以下命令是在所有数据库服务节点执行
[root@master ~]# ln -s /usr/local/mysql/bin/* /usr/local/bin/
我这里再次执行命令,还报错如下:
解决办法:
[root@master ~]# rpm -qa |grep -i dbd #查找下面的软件包
perl-DBD-MySQL-4.023-6.el7.x86_64
perl-DBD-SQLite-1.39-3.el7.x86_64
#卸载下面的软件包
[root@master ~]# rpm -e --nodeps perl-DBD-MySQL-4.023-6.el7.x86_64
[root@master ~]# yum -y install perl-DBD-MySQL #再次yum安装即可解决报错
最后检查命令执行成功,如下:
[root@manager ~]# masterha_check_repl --global_conf=/etc/masterha/masterha_default.cnf --conf=/etc/masterha/app1.cnf
返回以下信息,表示无误:
[root@manager ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &> /var/log/mha_manager.log &
注:可以多次执行上述命令,指定不同的app.cnf配置文件,以便监控多个MySQL集群,我这里就一个MySQL集群,所以只需要执行上述一条命令即可。
可以自行查看当前MySQL集群中目前的主是哪台服务器,我这里MySQL集群中的主是master主机,如下:
现在模拟master主机故障,然后再查看集群中的master是哪台,如下:
# 在master主机停止MySQL服务
[root@master ~]# systemctl stop mysqld
# 再次在slave2主机上查看当前的主是哪台?
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.20.3 # 可以看到当前的主是slave1这台备主
Master_User: mharep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 744
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 320
MHA Manager服务发生主从切换后,MHA manager服务会自动停止,且在manager_workdir(/masterha/app1/)目录下面生成app1.failover.complete文件,若要再次启动MHA,必须先确保没有这个文件,如果有app1.failover.complete或者app1.failover.error这个文件,则会报错如下:
只需要删除这个文件在将master主机指向新的master(也就是slave1)即可成功启动manager服务,如下:
# 删除
[root@manager app1]# rm -rf /masterha/app1/app1.failover.complete
# 在manager服务的日志中查看指定master的信息,如下:
[root@manager app1]# cat /masterha/app1/manager.log | grep MASTER
#如果服务已运行很久,那么肯定是看最后一条信息,日志里已经把指向新的master需要执行的指令记录了下来
#但是需要自己手动写密码
Fri Feb 21 17:57:37 2020 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='192.168.20.3', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=744, MASTER_USER='mharep', MASTER_PASSWORD='xxx';
Fri Feb 21 17:57:38 2020 - [info] Executed CHANGE MASTER.
# 在master主机上执行下面命令,以便指定slave2为主:
mysql> CHANGE MASTER TO MASTER_HOST='192.168.20.3', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=744, MASTER_USER='mharep', MASTER_PASSWORD='123.com';
#启动slave功能
mysql> start slave;
#再次启动manager服务
[root@manager app1]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &> /var/log/mha_manager.log &
[1] 16130
# 通过jobs -l查看到状态为“运行中”,即说明manager重新运行成功
[root@manager app1]# jobs -l
[1]+ 16130 运行中 nohup masterha_manager --conf=/etc/masterha/app1.cnf &>/var/log/mha_manager.log &
[root@manager ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf
[root@manager ~]# masterha_stop --conf=/etc/masterha/app1.cnf
[root@manager ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &>/tmp/mha_manager.log &
当有slave节点宕机时,manager服务是无法启动的,建议在配置文件中暂时注释掉宕机节点的信息,待修复后再取消注释。
[root@manager ~]# masterha_check_status --conf=/etc/masterha/app1.cnf #manager没有启动时的状态如下
app1 is stopped(2:NOT_RUNNING).
#启动manager服务再进行检查如下
[root@manager ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf &>/tmp/mha_manager.log &
[1] 19651
[root@manager ~]# masterha_check_status --conf=/etc/masterha/app1.cnf
app1 (pid:19651) is running(0:PING_OK), master:192.168.20.3
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。