PS:楼主技术能力有限,如有更好的解决思路请留下评论哈,谢谢。
前言
MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为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的manager节点单独部署在一台服务器中,另外因为这个环境要用在生产环境中担心manager节点出现单点故障问题,所以在其中一个slave服务器中部署多一个manager服务然后通过shell脚本监测manager节点的masterha进程,一旦masterha进程意外退出或者manager节点服务器意外宕机则自动启动slave节点中的manager服务对集群继续接管。
以下是本篇文章部署服务的大致结构
本文章mysql使用5.7.36版本 MHA版本使用0.58版本
主机IP | 节点/主机名 | 备注 |
---|
10.240.17.14 | manager | MHA管理节点 | 10.240.17.10 | master | Mysql-主库 | 10.240.17.11 | node01 | Mysql-从库 | 10.240.17.12 | node02 | Mysql-从库/MHA管理节点2 |
一、各服务器之间实现免密登录
1.添加各服务器间hosts指向
编辑/etc/hosts文件,尾行加入:
10.240.17.10 master
10.240.17.11 node01
10.240.17.12 node02
编辑/etc/hosts文件,尾行加入:
10.240.17.14 manager
10.240.17.11 node01
10.240.17.12 node02
编辑/etc/hosts文件,尾行加入:
10.240.17.14 manager
10.240.17.10 master
10.240.17.12 node02
10.240.17.14 manager
10.240.17.10 master
10.240.17.11 node01
2.四台服务器中分别生成密钥文件
分别在四台服务器中执行以下命令,生成密钥文件,密码为空,并将每台服务器的pub公钥文件传到其他三台服务器中,同时将pub公钥 内容追加到authorized_keys 中,以达到免密登录的效果。
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
分别为四台服务器的公钥文件重命名,避免弄混乱了,并将pub文件传输到其他节点~/.ssh 目录下
manager:
$ mv ~/.ssh/id_rsa.pub ~/.ssh/id_rsa_manager.pub
$ for i in master node01 node02; do scp ~/.ssh/id_rsa_manager.pub ${i}:~/.ssh/ ; done
master:
$ mv ~/.ssh/id_rsa.pub ~/.ssh/id_rsa_master.pub
$ for i in manager node01 node02; do scp ~/.ssh/id_rsa_master.pub ${i}:~/.ssh/ ; done
node01:
$ mv ~/.ssh/id_rsa.pub ~/.ssh/id_rsa_node01.pub
$ for i in manager master node02; do scp ~/.ssh/id_rsa_node01.pub ${i}:~/.ssh/ ; done
node02:
$ mv ~/.ssh/id_rsa.pub ~/.ssh/id_rsa_node02.pub
$ for i in manager master node01; do scp ~/.ssh/id_rsa_node02.pub ${i}:~/.ssh/ ; done
分别将其他节点的pub公钥内容追加到本节点的authorized_keys 中
manager:
$ for i in master node01 node02; do cat ~/.ssh/id_rsa_${i}.pub >> ~/.ssh/authorized_keys; done
master:
$ for i in manager node01 node02; do cat ~/.ssh/id_rsa_${i}.pub >> ~/.ssh/authorized_keys; done
node01:
$ for i in master manager node02; do cat ~/.ssh/id_rsa_${i}.pub >> ~/.ssh/authorized_keys; done
node02:
$ for i in master manager node01; do cat ~/.ssh/id_rsa_${i}.pub >> ~/.ssh/authorized_keys; done
测试:分别ssh到其他节点服务器看是否可以达到免密登录的效果
二、3台数据库节点安装Mysql服务
Mysql官网下载 网盘下载 楼主使用的是Mysql5.7.36的版本,以下操作请分别在3台数据库节点中操作
楼主使用root进行Mysql启动和管理 数据库数据和日志存放于/data/mysql_data和/data/mysql_logs目录下
检查一下服务器中是否存在mysql或者mariadb等相关组件或服务,有的话建议清理干净再进行安装:
$ rpm -qa | grep mariadb
$ rpm -qa | grep mysql
卸载请用如下命令:
$ yum remove 服务名 -y
解压安装包并修改目录名:
$ tar -zxvf mysql-5.7.36-el7-x86_64.tar.gz -C /usr/local/ && mv /usr/local/mysql-5.7.36 /usr/local/mysql
master,node01,node02三个节点中分别设置好mysql的配置文件,具体如下:
[client]
port = 3306
socket = /usr/local/mysql/mysql.sock
[mysqld]
user = root
server-id = 1
port = 3306
innodb_buffer_pool_size = 2800M
expire-logs-days = 7
max-binlog-size = 500M
innodb_log_file_size = 256M
slow_query_log = ON
slow_query_log_file=/data/mysql_logs/slow_query.log
socket = /usr/local/mysql/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql_data
log_error = /data/mysql_logs/mysql-error.log
log-bin = /data/mysql_data/master-bin
log-slave-updates = true
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
pid-file = /data/mysql_data/master.pid
gtid-mode = ON
enforce-gtid-consistency = ON
[client]
port = 3306
socket = /usr/local/mysql/mysql.sock
[mysqld]
user = root
server-id = 2
port = 3306
innodb_buffer_pool_size = 2800M
expire-logs-days = 7
max-binlog-size = 500M
innodb_log_file_size = 256M
slow_query_log = ON
slow_query_log_file = /data/mysql_logs/slow_query.log
socket = /usr/local/mysql/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql_data
log_error = /data/mysql_logs/mysql-error.log
pid-file = /data/mysql_data/node01.pid
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
log-bin = /data/mysql_data/master-bin
gtid-mode = ON
enforce-gtid-consistency = ON
[client]
port = 3306
socket = /usr/local/mysql/mysql.sock
[mysqld]
user = root
server-id = 3
port = 3306
innodb_buffer_pool_size = 2800M
expire-logs-days = 7
max-binlog-size = 500M
innodb_log_file_size = 256M
slow_query_log = ON
slow_query_log_file = /data/mysql_logs/slow_query.log
socket = /usr/local/mysql/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql_data
log_error = /data/mysql_logs/mysql-error.log
pid-file = /data/mysql_data/node02.pid
relay-log = relay-log-bin
relay-log-index = slave-relay-bin.indexc
read_only = 1
log-bin = /data/mysql_data/master-bin
gtid-mode = ON
enforce-gtid-consistency = ON
安装autoconf依赖包:
$ yum install -y autoconf
安装mysql
$ cd /usr/local/mysql/bin
$ ./mysqld --initialize --user=root --basedir=/usr/local/mysql --datadir=/data/mysql_data
没出现报错的话此时可以进入/data/mysql_logs/mysql-error.log 文件中最下面一行查看初始密码,可以使用该密码登录数据库进行修改密码操作。
拷贝mysql启动程序到/etc/init.d/ 目录下
$ cp -a /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
启动mysql
service mysqld start
配置环境变量,方便使用mysql命令
$ vim /etc/profile
export MYSQL_HOME=/usr/local/mysql
export PATH=$PATH:$MYSQL_HOME/bin
使环境变量生效
$ source /etc/profile
用日志文件中记录的初始密码登录mysql,修改密码
$ mysql -uroot -p
mysql中修改密码为111111,建议大家尽量设置复杂密码哈
mysql> alter user 'root'@'localhost' identified by '111111';
mysql> flush privileges;
另外下面两条语句一条是放通所有主机远程访问mysql,一条是放通指定IP访问mysql,看你们自己的需求了哈,这里最少要放行manager服务器的IP,不然后期MHA无法监测到主从集群的状态,还需要放行node02服务器的IP,因为node02服务器需要运行监测脚本及备用mha服务
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '111111' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'指定的IP' IDENTIFIED BY '111111' WITH GRANT OPTION;
常用的命令
$ service mysqld start
$ service mysqld stop
$ service mysqld restart
$ service mysqld status
三、启动mysql主从集群
在主节点master数据库中创建主从复制使用的用户
mysql> create user slave_user;
mysql> grant replication slave on *.* to slave_user identified by '111111';
mysql> flush privileges;
mysql> grant all on *.* to root identified by '111111';
分别在两个从节点node01和node02数据库中执行
mysql> CHANGE MASTER TO MASTER_HOST='10.240.17.10',MASTER_PORT=3306,MASTER_AUTO_POSITION=1,MASTER_USER='slave_user',MASTER_PASSWORD='111111';
mysql> start slave;
mysql> show slave status\G
在主库中创建一个库做测试,可查看从库是否同时创建了相应的库
mysql> create database 123;
由于楼主业务环境要求,这里关闭mysql的自动提交功能
mysql> set autocommit=OFF;
四、安装MHA
安装epel扩展包
$ yum install -y epel-release
安装MHA依赖的perl包
$ yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager
四个节点服务器都安装mha4mysql-node 包
$ rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm
manager节点服务器安装mha4mysql-manager 包
$ rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
在三个mysql服务器中添加mha监控用户并指定manager服务器的IP可访问
mysql> grant all privileges on *.* to 'mha'@'10.240.17.14' identified by '111111';
manager服务器/etc/masterha/mha.cnf 中添加MHA相关配置
[server default]
manager_log=/usr/local/masterha/manager.log
manager_workdir=/usr/local/masterha
master_binlog_dir=/data/mysql_data/
master_ip_failover_script=/usr/local/bin/master_ip_failover
ping_interval=1
remote_workdir=/usr/local/masterha/logbin
user=mha
password=111111
repl_user=slave_user
repl_password=111111
ssh_user=root
[server1]
hostname=10.240.7.134
port=3306
ssh_port=22
[server2]
candidate_master=1
check_repl_delay=0
hostname=10.240.7.132
port=3306
ssh_port=22
[server3]
hostname=10.240.7.133
port=3306
ssh_port=22
manager服务器/usr/local/bin 中添加master_ip_failover切换脚本
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
my (
$command, $ssh_user, $orig_master_host,
$orig_master_ip,$orig_master_port, $new_master_host, $new_master_ip,$new_master_port
);
my $vip = '10.240.17.15/24';
my $brdc = '10.240.17.255';
my $ifdev = 'ens160';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig ens160:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens160:$key down";
GetOptions(
'command=s' => \$command,
'ssh_user=s' => \$ssh_user,
'orig_master_host=s' => \$orig_master_host,
'orig_master_ip=s' => \$orig_master_ip,
'orig_master_port=i' => \$orig_master_port,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s' => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
);
exit &main();
sub main {
print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
if ( $command eq "stop" || $command eq "stopssh" ) {
my $exit_code = 1;
eval {
print "Disabling the VIP on old master: $orig_master_host \n";
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "start" ) {
my $exit_code = 10;
eval {
print "Enabling the VIP - $vip on the new master - $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";
exit 0;
}
else {
&usage();
exit 1;
}
}
sub start_vip() {
`ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}
sub stop_vip() {
return 0 unless ($ssh_user);
`ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
sub usage {
print
"Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}
到此MHA配置完成
五、Manage工具测试
$ masterha_check_ssh --conf=/etc/masterha/mha.cnf
以下输出表示正常,IP跟文章不一致不用管,楼主测试环境用的是其他IP 如果报Binlog setting check failed!错误,那么有可能是master服务器保存二进制日志文件地址错误
- 检查 manager 与数据库节点间的主从复制是否正常
$ masterha_check_repl --conf=/etc/masterha/mha.cnf
以下输出表示正常,IP跟文章不一致不用管,楼主测试环境用的是其他IP master主节点服务器绑定VIP
$ ifconfig ens160:1 10.240.7.15/24
$ ifconfig ens160:1 del 10.240.7.15
安装supervisor使用supervisor进行服务管理
$ yum install -y supervisor
在/etc/supervisord.d 目录中添加mha.ini配置文件
[program:mha]
directory=/bin
command=masterha_manager --conf=/etc/masterha/mha.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /usr/local/masterha/manager.log 2>&1 &
autostart=true
autorestart=false
startsecs=1
user = root
stderr_logfile=/var/log/supervisor/mha_stderr.log
stdout_logfile=/var/log/supervisor/mha_stdout.log
redirect_stderr = true
stdout_logfile_maxbytes = 20MB
stdout_logfile_backups = 20
启动supervisor服务
$ systemctl start supervisord
因配置了mha跟随supervisor服务启动因此启动了supervisor服务同时会把mha也启动了,现在可以直接查看mha的状态
$ supervisorctl status mha
$ supervisorctl start mha
$ supervisorctl stop mha
查看mha监测mysql集群的状态
$ masterha_check_status --conf=/etc/masterha/mha.cnf
至此,MHA部分安装完成,接下来进行高可用测试,楼主测试过程中发现manager节点一旦出现问题了就无法自动进行VIP的切换,因此在Node02节点中运行了一个循环脚本用于监测manager节点的masterha进程是否正常运行,一旦意外退出了或者manager服务器宕机了,就在Node02节点中启动masterha服务进行高可用的接管(楼主测试过同时启动两个masterha进程会失败,其中一个进程会提示已有服务在监控主库的运作,所以楼主这里采用shell脚本作为辅助)。
五、Shell脚本监测Manager节点解决单点故障问题
在Node02节点服务器中安装mha4mysql-manager
$ rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
在/etc/masterha 及/usr/local/bin 两个目录分别放入配置文件及切换VIP的脚本 Node02服务器中执行操作
$ rsync -avzP manager:/etc/masterha/mha.cnf /etc/masterha/
$ rsync -avzP manager:/usr/local/bin/master_ip_failover /usr/local/bin/
添加以下配置信息到supervisor配置目录下(/etc/supervisord.d/)
$ vim /etc/supervisord.d/mha.ini
[program:mha]
directory=/bin
command=masterha_manager --conf=/etc/masterha/mha.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /usr/local/masterha/manager.log 2>&1 &
autostart=false
autorestart=false
startsecs=1
user = root
stderr_logfile=/var/log/supervisor/mha_stderr.log
stdout_logfile=/var/log/supervisor/mha_stdout.log
redirect_stderr = true
stdout_logfile_maxbytes = 20MB
stdout_logfile_backups = 20
添加shell监测脚本,用于监测manager节点中mha服务的运行状态,楼主脚本写得较为简单,有需要请根据环境自行修改
$ vim /root/monitor_masterha.sh
while true
do
time_node=$(date "+%Y-%m-%d %H:%M:%S")
ssh root@manager "ps aux | grep /etc/masterha/mha.cnf" | grep -v grep
if [ ${?} -eq "0" ];then
echo "于${time_node}时间节点,监测manager节点masterha进程运行正常" >> /root/monitor_masterha.log
else
/bin/rsync -avzP mysqlmha-manager:/etc/masterha/mha.cnf /etc/masterha/
/bin/supervisorctl start mha
echo "masterha于${time_node}启动了。" >> /root/monitor_masterha.log
exit 0
fi
sleep 5
done
同时添加脚本的supervisor配置文件利用supervisor管理启动脚本
$ vim /etc/supervisord.d/monitor_masterha.ini
[program:monitor_masterha]
directory=/root
command=/usr/bin/bash /root/monitor_masterha.sh &
autostart=true
autorestart=false
startsecs=1
user = root
stderr_logfile=/var/log/supervisor/monitor_masterha_stderr.log
stdout_logfile=/var/log/supervisor/monitor_masterha_stdout.log
redirect_stderr = true
stdout_logfile_maxbytes = 20MB
stdout_logfile_backups = 20
配置完成后启动monitor_masterha脚本即可,如manager节点mha服务退出就会启动node02服务器上的mha服务接管mha
$ supervisorctl start monitor_masterha
六、数据库集群的故障测试及切换测试
利用下面的脚本循环插入2万条数据到mysql集群中,在插入过程中测试关掉master节点的mysql服务,查看node01节点是否接管集群成为主库
$ vim /root/insert_mysql.sh
HOSTNAME="10.240.17.15"
PORT="3306"
USERNAME="root"
PASSWORD="111111"
DBNAME="abc"
TABLENAME="test"
create_db_sql="create database IF NOT EXISTS ${DBNAME}"
mysql -h${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "${create_db_sql}"
create_table_sql="create table IF NOT EXISTS ${TABLENAME} ( name varchar(20), id int(11) default 0 )"
mysql -h${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e"${create_table_sql}"
for i in {1..20000}
do
insert_sql="insert into ${TABLENAME} values('${i}',${i})"
mysql -h${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e"${insert_sql}"
echo "已插入第${i}条数据。"
echo "========================"
done
启动插入数据脚本插入数据到数据库
$ bash /root/insert_mysql.sh
查看node01和node02的数据库数据条数 数据同步插入中,集群正常,接下来停掉master节点mysql服务
$ service mysqld stop
此时查看node01节点状态,发现VIP已经切换到node01服务器上,并且node02查看mysql集群状态发现主库指向node01的IP,集群切换成功(中间恢复连接耗时约30秒左右) 接下来测试将原master服务器恢复数据库数据并重新加入集群成为从节点 具体恢复步骤:1.通过mysqldump备份node01服务器数据-->2.master服务器启动mysql服务通过source导入备份数据-->3.查询出node01的binlog日志中的pos值-->4.master服务器stop slave停止集群后通过change master to命令重新加入集群,然后再start slave启动集群-->5.添加mha配置信息被删掉的部分-->6.启动mha服务
现在查看master和node01的数据差异
- 通过mysqldump备份node01服务器数据
$ mysqldump -uroot -p -A --master-data=2 >/root/mysql.sql
该mysql.sql文件传输到master服务器中
- master服务器启动mysql服务通过source导入备份数据
$ service mysqld start
$ mysql -uroot -p
mysql> source /root/mysql.sql;
- 查询出node01的binlog日志中的pos值
master服务器中执行或node01服务器中执行都可,主要查询的是导出的备份文件mysql.sql
$ grep MASTER_LOG_FILE ./mysql.sql | grep master-bin.000004
- master服务器stop slave停止集群后通过change master to命令重新加入集群,然后再start slave启动集群
mysql> stop slave;
mysql> CHANGE MASTER TO MASTER_HOST='10.240.7.132', MASTER_PORT=3306, MASTER_LOG_FILE='master-bin.000004', MASTER_LOG_POS=399358, MASTER_USER='root', MASTER_PASSWORD='111111';
mysql> start slave;
mysql> show slave status\G
再次对比master与node01节点的数据差异,目前已恢复一致
- 添加mha配置信息被删掉的部分
$ vim /etc/masterha/mha.cnf
[server default]
manager_log=/usr/local/masterha/manager.log
manager_workdir=/usr/local/masterha
master_binlog_dir=/data/mysql_data/
master_ip_failover_script=/usr/local/bin/master_ip_failover
password=111111
ping_interval=1
remote_workdir=/usr/local/masterha/logbin
repl_password=111111
repl_user=slave_user
ssh_user=root
user=mha
[server1]
hostname=10.240.17.11
port=3306
ssh_port=22
[server2]
candidate_master=1
check_repl_delay=0
hostname=10.240.17.10
port=3306
ssh_port=22
[server3]
hostname=10.240.17.12
port=3306
ssh_port=22
- 重新启动mha服务
$ supervisorctl start mha
最后请自行测试以下同时关掉master节点的mysql服务和manager的mha服务,这时监测脚本就会在node02节点中启动mha服务将VIP切换到node01中 楼主使用prometheus进行mysql集群的监控和告警,如有需要请自行写告警脚本进行告警哈
总结
到此Mysql高可用集群搭建完毕,楼主个人能力有限,脚本写得简易,请勿喷,另外如果有什么问题欢迎指出,谢谢。
|