一、实验思路
1.MHA架构
1)数据库安装
2)一主两从(基于GITDS)
3)MHA搭建
2.故障模拟
1)主库失效
2)备选主库成为主库
3)原故障主库恢复重新加入到MHA成为从库
二、准备环境
1.服务器规划
服务器 | 系统 | IP | 需要安装 |
---|---|---|---|
MHA manager 节点服务器 | CentOS7.4(64 位) | 10.32.176.80 | Mysq5.7、MHA node 和 manager 组件 |
Master 节点服务器 | CentOS7.4(64 位) | 10.32.176.81 | mysql5.7、MHA node 组件 |
Slave1 节点服务器 | CentOS7.4(64 位) | 10.32.176.82 | mysql5.7、MHA node 组件 |
Slave2节点服务器 | CentOS7.4(64 位) | 10.32.176.86 | mysql5.7、MHA node 组件 |
2.关闭防火墙
操作节点:所有
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
三、mysql安装
1.下载mysql安装包
MySQL 5.7 Linux安装包下载:https://dev.mysql.com/downloads/mysql/
2.查询并卸载系统自带的Mariadb
rpm -qa | grep mariadb
rpm -e --nodeps 文件名
3.建立一个mysql用户和mysql用户组
# 添加mysql用户组 groupadd mysql
# 添加mysql用户 useradd -g mysql mysql -d /home/mysql
# 修改mysql用户的登陆密码 passwd mysql
4.创建临时目录、数据目录和日志目录
mkdir -p /home/mysql/3306/data
mkdir -p /home/mysql/3306/log
mkdir -p /home/mysql/3306/tmp
5.安装包上传至服务器/usr/local
目录下
# 解压缩 tar -xvf mysql-5.7.35-linux-glibc2.12-x86_64.tar
# 会得到一个mysql-5.7.35-linux-glibc2.12-x86_64.tar.gz文件,再解压缩 tar -zxvf mysql-5.7.35-linux-glibc2.12-x86_64.tar.gz
# 建立软链接,便于以后版本升级 ln -s mysql-5.7.35-linux-glibc2.12-x86_64 mysql
# 修改mysql文件夹下所有文件的用户和用户组 chown -R mysql:mysql mysql/
6.创建配置文件
# 创建配置文件 cd /etc
# 在my.cnf文件中添加对应的配置项,文章末尾会提供一个默认的my.cnf配置 vi my.cnf
7.安装数据库
# 初始化数据库,并指定启动mysql的用户 ./mysqld --initialize --user=mysql
这里最好指定启动mysql的用户名,否则就会在启动MySQL时出现权限不足的问题
8.设置开机自启动服务
# 复制启动脚本到资源目录 cp ./support-files/mysql.server /etc/rc.d/init.d/mysqld
# 增加mysqld服务控制脚本执行权限 chmod +x /etc/rc.d/init.d/mysqld
# 将mysqld服务加入到系统服务 chkconfig --add mysqld
# 检查mysqld服务是否已经生效 chkconfig --list mysqld
# 切换至mysql用户,启动mysql service mysqld start
9.配置环境变量
为了更好的操作mysql,配置环境变量
# 切换至mysql用户 su - mysql
# 修改配置文件
vi .bash_profile
export PATH=$PATH:/usr/local/mysql/bin
# 立即生效
source .bash_profile
10.登陆 修改密码
# 登陆mysql mysql -uroot -p(注:安装完成后,在my.cnf中配置的datadir目录下生成一个error.log文件,里面记录了root用户的随机密码。)
# 修改root用户密码 set password for root@localhost=password("mect888!");
四、搭建基于GITDs的一主两从数据库集群
1.准备mysql的配置文件my.cnf
vim /etc/my.cnf
master my.cnf配置如下:
[client]
port = 3306
socket = /home/mysql/3306/tmp/mysql.sock
[mysqld]
server-id = 1
port = 3306
basedir = /usr/local/mysql
datadir = /home/mysql/3306/data
tmpdir = /home/mysql/3306/tmp
socket = /home/mysql/3306/tmp/mysql.sock
pid-file = /home/mysql/3306/log/mysql.pid
log_error = /home/mysql/3306/log/error.log # 数据库错误日志文件
slow_query_log = 1 # 慢查询sql日志设置
long_query_time = 1 # 慢查询时间;超过1秒则为慢查询
slow_query_log_file = /home/mysql/3306/log/slow.log # 慢查询日志文件
log_queries_not_using_indexes = 1 # 检查未使用到索引的sql
log_throttle_queries_not_using_indexes = 5 # 用来表示每分钟允许记录到slow log的且未使用索引的SQL语句次数。该值默认为0,表示没有限制
min_examined_row_limit = 100 # 检索的行数必须达到此值才可被记为慢查询,查询检查返回少于该参数指定行的SQL不被记录到慢查询日志
expire_logs_days = 5 # MySQL binlog日志文件保存的过期时间,过期后自动删除
# 主从复制设置
log-bin = /home/mysql/3306/data/master
binlog_format = ROW # binlog记录内容的方式,记录被操作的每一行
log-slave-updates=1
gtid-mode=ON
enforce-gtid-consistency=ON
slave1 my.cnf配置如下:
[client]
port = 3306
socket = /home/mysql/3306/tmp/mysql.sock
[mysqld]
server-id = 2
port = 3306
basedir = /usr/local/mysql
datadir = /home/mysql/3306/data
tmpdir = /home/mysql/3306/tmp
socket = /home/mysql/3306/tmp/mysql.sock
pid-file = /home/mysql/3306/log/mysql.pid
log_error = /home/mysql/3306/log/error.log # 数据库错误日志文件
slow_query_log = 1 # 慢查询sql日志设置
long_query_time = 1 # 慢查询时间;超过1秒则为慢查询
slow_query_log_file = /home/mysql/3306/log/slow.log # 慢查询日志文件
log_queries_not_using_indexes = 1 # 检查未使用到索引的sql
log_throttle_queries_not_using_indexes = 5 # 用来表示每分钟允许记录到slow log的且未使用索引的SQL语句次数。该值默认为0,表示没有限制
min_examined_row_limit = 100 # 检索的行数必须达到此值才可被记为慢查询,查询检查返回少于该参数指定行的SQL不被记录到慢查询日志
expire_logs_days = 5 # MySQL binlog日志文件保存的过期时间,过期后自动删除
# 主从复制设置
log-bin = /home/mysql/3306/data/slave1
binlog_format = ROW # binlog记录内容的方式,记录被操作的每一行
log-slave-updates=1
gtid-mode=ON
enforce-gtid-consistency=ON
slave2 my.cnf配置如下:
[client]
port = 3306
socket = /home/mysql/3306/tmp/mysql.sock
[mysqld]
server-id = 3
port = 3306
basedir = /usr/local/mysql
datadir = /home/mysql/3306/data
tmpdir = /home/mysql/3306/tmp
socket = /home/mysql/3306/tmp/mysql.sock
pid-file = /home/mysql/3306/log/mysql.pid
log_error = /home/mysql/3306/log/error.log # 数据库错误日志文件
slow_query_log = 1 # 慢查询sql日志设置
long_query_time = 1 # 慢查询时间;超过1秒则为慢查询
slow_query_log_file = /home/mysql/3306/log/slow.log # 慢查询日志文件
log_queries_not_using_indexes = 1 # 检查未使用到索引的sql
log_throttle_queries_not_using_indexes = 5 # 用来表示每分钟允许记录到slow log的且未使用索引的SQL语句次数。该值默认为0,表示没有限制
min_examined_row_limit = 100 # 检索的行数必须达到此值才可被记为慢查询,查询检查返回少于该参数指定行的SQL不被记录到慢查询日志
expire_logs_days = 5 # MySQL binlog日志文件保存的过期时间,过期后自动删除
# 主从复制设置
log-bin = /home/mysql/3306/data/slave2
binlog_format = ROW # binlog记录内容的方式,记录被操作的每一行
log-slave-updates=1
gtid-mode=ON
enforce-gtid-consistency=ON
2.重新启动mysql
service mysql restart
3.在master和slave1授权
grant replication slave on *.* to 'rep'@'%' identified by '123';
flush privileges;
4.slave1和slave2配置为master的从
change master to master_host='10.32.176.81',master_port=3306,master_user='rep',master_password='123',master_auto_position=1;
start slave;
在 Slave1、Slave2 节点查看数据同步结果
show slave status\G
确保 IO 和 SQL 线程都是 Yes,代表同步正常。
五、MHA高可用搭建
1.MHA软件依赖安装
所有服务器上都安装 MHA 依赖的环境,首先安装 epel 源
yum install epel-release --nogpgcheck -y
yum install perl-DBD-MySQL \
perl-Config-Tiny \
perl-Time-HiRes \
perl-Mail-Sender \
perl-Mail-Sendmail \
perl-MIME-Base32 \
perl-MIME-Charset \
perl-MIME-EncWords \
perl-Params-Classify \
perl-Params-Validate.x86_64 \
perl-Log-Dispatch \
perl-Parallel-ForkManager \
net-tools -y
2.安装 MHA 软件包,先在所有服务器上必须先安装 node 组件
对于每个操作系统版本不一样,这里 CentOS7.6 选择 0.57 版本。
在所有服务器上必须先安装 node 组件,最后在 MHA-manager 节点上安装 manager 组件,因为 manager 依赖 node 组件。
cd /opt
tar zxvf mha4mysql-node-0.57.tar.gz
cd mha4mysql-node-0.57
perl Makefile.PL
make && make install
3.在 MHA manager 节点上安装 manager 组件
cd /opt
tar zxvf mha4mysql-manager-0.57.tar.gz
cd mha4mysql-manager-0.57
perl Makefile.PL
make && make install
4.配置ssh互信
1)所有服务器上都使用root产生空密码密钥对
[root@mgr ~]# ssh-keygen -P "" -f /root/.ssh/id_rsa
[root@master ~]# ssh-keygen -P "" -f /root/.ssh/id_rsa
[root@slave1 ~]# ssh-keygen -P "" -f /root/.ssh/id_rsa
[root@slave2 ~]# ssh-keygen -P "" -f /root/.ssh/id_rsa
2)将master,slave1,slave2上产生的公钥拷给mgr管理节点上对应的路径
[root@master ~]# scp /root/.ssh/id_rsa.pub 10.32.176.80:/root/.ssh/master_id_pub
[root@slave1 ~]# scp /root/.ssh/id_rsa.pub 10.32.176.80:/root/.ssh/slave1_id_pub
[root@slave2 ~]# scp /root/.ssh/id_rsa.pub 10.32.176.80:/root/.ssh/slave2_id_pub
3)在mgr管理节点将所有的公钥(包括自己的)都追加到同一个authorized_keys文件里
[root@mgr ~]# cd /root/.ssh/
[root@mgr.ssh]# cat master_id_pub slave1_id_pub slave2_id_pub id_rsa.pub >> authorized_keys
4)在mgr管理节点上将authorized_keys文件分发给master,slave1,slave2上
[root@mgr.ssh]# for i in 81 82 86; do scp authorized_keys 10.32.176.$i:/root/.ssh/; done
5.在 manager 节点上配置 MHA
1)在 manager 节点上复制相关脚本到/usr/local/bin 目录
cp -rp /opt/mha4mysql-manager-0.57/samples/scripts /usr/local/bin
//拷贝后会有四个执行文件
ll /usr/local/bin/scripts/
master_ip_failover
master_ip_online_change
power_manager
send_report
脚本名称 | 作用 |
---|---|
master_ip_failover | 自动切换时 VIP 管理的脚本 |
master_ip_online_change | 在线切换时 vip 的管理 |
power_manager | 故障发生后关闭主机的脚本 |
send_report | 因故障切换后发送报警的脚本 |
(2)复制上述的自动切换时 VIP 管理的脚本到 /usr/local/bin 目录,这里使用master_ip_failover脚本来管理 VIP 和故障切换
cp /usr/local/bin/scripts/master_ip_failover /usr/local/bin
(3)修改内容如下:(删除原有内容,直接复制并修改vip相关参数)
vim /usr/local/bin/master_ip_failover
#!/usr/bin/env perl
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.32.176.100'; #指定vip的地址
my $brdc = '10.32.176.255'; #指定vip的广播地址
my $ifdev = 'ens192'; #指定vip绑定的网卡
my $key = '1'; #指定vip绑定的虚拟网卡序列号
my $ssh_start_vip = "/sbin/ifconfig ens192:$key $vip"; #代表此变量值为ifconfig ens192:1 10.32.176.100
my $ssh_stop_vip = "/sbin/ifconfig ens192:$key down"; #代表此变量值为ifconfig ens192:1 10.32.176.100 down
my $exit_code = 0; #指定退出状态码为0
#my $ssh_start_vip = "/usr/sbin/ip addr add $vip/24 brd $brdc dev $ifdev label $ifdev:$key;/usr/sbin/arping -q -A -c 1 -I $ifdev $vip;iptables -F;";
#my $ssh_stop_vip = "/usr/sbin/ip addr del $vip/24 dev $ifdev label $ifdev:$key";
##################################################################################
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 \"`;
}
## A simple system call that disable the VIP on the old_master
sub stop_vip() {
`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";
}
(4)创建mha监控用户
master,slave1,slave2三台mysql服务器上创建mha监控用户, 需要对管理节点授权(授权时IP为管理节点IP)
mysql> grant all on *.* to mha@'10.32.176.80' identified by '123';
mysql> flush privileges;
(5)创建 MHA 软件目录并拷贝配置文件,这里使用app1.cnf配置文件来管理 mysql 节点服务器
mkdir /etc/mha
cp /opt/mha4mysql-manager-0.57/samples/conf/app1.cnf /etc/mha
vim /etc/masterha/app1.cnf
[server default]
# 设置监控用户和密码
user=mha
password=123
# 设置复制环境中的复制用户和密码
repl_user=rep
repl_password=123
# 设置ssh的登录用户名
ssh_user=root
# 设置监控主库,发送ping包的时间间隔,默认是 3 秒,尝试三次没有回应的时候自动进行failover
ping_interval=3
# 设置mgr的工作目录
manager_workdir=/data/mha/app1
# 设置mysql master 保存 binlog 的目录,以便 MHA 可以找到 master 的二进制日志
master_binlog_dir=/home/mysql/3306/data
# 设置 master 的 pid 文件
master_pid_file=/home/mysql/3306/log/mysql.pid
# 设置 mysql master 在发生切换时保存 binlog 的目录(在mysql master上创建这个目录)
remote_workdir=/tmp/data
# 设置 mgr 日志文件
manager_log=/data/mha/app1/app1-3306.log
# MHA 到 master 的监控之间出现问题,MHA Manager 将会尝试从slave1和slave2登录到master上
secondary_check_script=/usr/bin/masterha_secondary_check -s 10.32.176.82 -s 10.32.176.86 --user=root --port=22 --master_host=10.32.176.81 --master_port=3306
# 设置自动 failover 时候的切换脚本
master_ip_failover_script=/usr/local/bin/master_ip_failover
[server1]
hostname=10.32.176.81
port=3306
candidate_master=1
[server2]
hostname=10.32.176.82
port=3306
candidate_master=1
[server3]
hostname=10.32.176.86
port=3306
no_master=1
(6)第一次配置需要在master节点手动开启虚拟IP
/usr/sbin/ifconfig ens192:1 10.32.176.100/24
(7)检查ssh互信状态和集群状态
[root@mgr ~]# masterha_check_ssh --conf=/etc/mha/app1.conf
......
Wed May 25 10:40:41 2021 - [info] All SSH connection tests passed successfully.
[root@mgr ~]# masterha_check_repl --conf=/etc/mha/app1.conf
......
MySQL Replication Health is OK.
(8)启动MHA-Mgr状态监控
先检查状态, 为NOT_RUNNING
状态
[root@mgr ~]# masterha_check_status --conf=/etc/mha/app1.conf
app1 is stopped(2:NOT_RUNNING).
六、开启MHA Manager监控
[root@mgr ~]# nohup masterha_manager --conf=/etc/mha/app1.conf --ignore_last_failover &
[root@mgr ~]# masterha_check_status --conf=/etc/mha/app1.conf
app1 (pid:10121) is running(0:PING_OK), master:10.32.176.81
查看日志变化
tail -f /data/mha/app1/app1-3306.log
七、故障模拟
1.在 manager 节点上监控观察日志记录
tail -f /data/mha/app1/app1-3306.log
2.在 Master 节点上停止mysql服务
service mysqld stop
或者kill -9 pid
同时查看app1-3306.log的变化
ps:
正常自动切换一次后,MHA 进程会退出。HMA 会自动修改 app1.cnf 文件内容,将宕机的 mysql1 节点删除。
查看 mysql2 是否接管 VIP
八、故障修复
1.启动原master(模拟故障)的mysql服务
service mysqld start
2.进入数据库执行以下命令,配置为新的slave1
mysql> change master to master_host='10.32.176.82', master_user='rep',master_password='123',master_port=3306, master_auto_position=1;
mysql> start slave;
mysql> show slave status\G
Slave_IO_State: Waiting for master to send event
Master_Host: 10.32.176.82 确认此IP为slave1的IP(也就是现在的master的IP)
Master_User: rep
Master_Port: 3306
......
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
3.重新检查ssh互信状态和集群状态
[root@mgr ~]# masterha_check_ssh --conf=/etc/mha/app1.conf
......
Wed May 25 10:40:41 2021 - [info] All SSH connection tests passed successfully.
[root@mgr ~]# masterha_check_repl --conf=/etc/mha/app1.conf
......
MySQL Replication Health is OK.
4.启动MHA-Mgr状态监控
先检查状态, 为NOT_RUNNING
状态
[root@mgr ~]# masterha_check_status --conf=/etc/mha/app1.conf
app1 is stopped(2:NOT_RUNNING).
开启MHA Manager监控
[root@mgr ~]# nohup masterha_manager --conf=/etc/mha/app1.conf --ignore_last_failover &
[root@mgr ~]# masterha_check_status --conf=/etc/mha/app1.conf
app1 (pid:10121) is running(0:PING_OK), master:10.32.176.82