传统的MySQL主从架构存在的问题
MHA(Master High Availability)目前在 MySQL 高可用方面是一个相对成熟的解决方案,它由日本人 youshimaton 开发,是一套优秀的作为 MySQL 高可用性环境下故障切换和主从提升的高可用软件。在 MySQL 故障切换过程中,MHA 能做到 0~30 秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA 能最大程度上保证数据库的一致性,以达到真正意义上的高可用。MHA 由两部分组成:MHA Manager(管理节点)和 MHA Node(数据节点)。MHA Manager可以独立部署在一台独立的机器上管理多个Master-Slave集群,也可以部署在一台Slave上。当 Master 出现故障是,它可以自动将最新数据的Slave 提升为新的 Master,然后将所有其他的 Slave 重新指向新的 Master。整个故障转移过程对应用程序是完全透明的。
1.从宕机崩溃的 Master 保存二进制日志事件(binlog event);
2. 识别含有最新更新的 Slave;
3. 应用差异的中继日志(relay log)到其他 Slave;
4. 应用从 Master 保存的二进制日志事件;
5. 提升一个 Slave 为新的 Master;
6. 使其他的 Slave 连接新的 Master 进行复制;
目前 MHA 主要支持一主多从的架构,要搭建 MHA,要求一个复制集群必须最少有 3 台数据库服务器,一主二从,即一台充当 Master,一台充当备用 Master,另一台充当从库。出于成本考虑,淘宝在此基础上进行了改造,目前淘宝开发的 TMHA 已经支持一主一从。
在 MHA 自动故障切换的过程中,MHA 试图从宕掉的主服务器上保存二进制日志,最大程度保证数据的不丢失,但这并不总是可行的。例如,如果主服务器硬件故障或无法通过 SSH 访问,MHA 没有办法保存二进制日志,只能进行故障转移而丢失了最新数据。拓:MySQL 服务挂了,但是可以从服务器拷贝二进制。但如果硬件宕机或者 SSH 不能连接,不能获取到最新的 binlog 日志,如果复制出现延迟,会丢失数据。使用 MySQL5.5 的半同步复制,可以大大降低数据丢失的风险。MHA 可以和半同步复制结合起来。如果只有一个 Slave 已经收到了最新的二进制日志,MHA 可以将最新的二进制日志应用于其他所有 Slave 服务器上,保持数据一致性。最新版 0.56 版本,增加了支持 GTID 的功能,建议在 MySQL5.6 及之后版本使用。MySQL5.5建议使用管理节点版本 0.55,数据节点 0.54。
1、MHA架构
在三台 MySQL 节点上分别安装数据库 MySQL 版本请使用 5.6.36,cmake 版本使用 2.8.6
mysql-master:192.168.10.10 主服务器
mysql-slave1:192.168.10.20 从服务器/备选服务器
mysql-slave2:192.168.10.30 从服务器
vip(漂移地址):192.168.10.100
mha-manger:192.168.10.40
1.安装编译依赖的环境
[root@master ~]# yum -y install ncurses-devel gcc-c++ perl-Module-Install
2.安装 gmake 编译软件
[root@master ~]# tar zxvf cmake-2.8.6.tar.gz
[root@master ~]# cd cmake-2.8.6
[root@master cmake-2.8.6]# ./configure
[root@master cmake-2.8.6]# gmake && gmake install
3.安装 MySQL 数据库
[root@master ~]# tar -zxvf mysql-5.6.36.tar.gz
[root@master ~]# cd mysql-5.6.36
[root@master mysql-5.6.36]# cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_EXTRA_CHARSETS=all -DSYSCONFDIR=/etc
[root@master mysql-5.6.36]# make && make install
[root@master mysql-5.6.36]# cp support-files/my-default.cnf /etc/my.cnf
[root@master mysql-5.6.36]# cp support-files/mysql.server /etc/rc.d/init.d/mysqld
[root@master ~]# chmod +x /etc/rc.d/init.d/mysqld
[root@master ~]# chkconfig --add mysqld
[root@master ~]# echo "PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile
[root@master ~]# source /etc/profile
[root@master ~]# groupadd mysql
[root@master ~]# useradd -M -s /sbin/nologin mysql -g mysql
[root@master ~]# chown -R mysql.mysql /usr/local/mysql
[root@master ~]# mkdir -p /data/mysql
[root@master ~]# /usr/local/mysql/scripts/mysql_install_db --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --user=mysql
4.修改 Master 的主配置文件/etc/my.cnf 文件,三台服务器的 server-id 不能一样,另外两台写 2 和 3 即可!写入内容如下:
[root@master ~]# cat /etc/my.cnf
[mysqld]
server-id = 1
log_bin = master-bin
log-slave-updates = true
[root@slave1 ~]# vim /etc/my.cnf
[mysqld]
server-id = 2 //增加
log_bin = master-bin
relay-log = relay-log-bin //增加
relay-log-index = slave-relay-bin.index //增加
这里要注意 server-id 不能相同。
需要删除字符集utf8的语句
[root@slave2 ~]# vim /etc/my.cnf
[mysqld]
server-id = 3 //增加
log_bin = master-bin
relay-log = relay-log-bin //增加
relay-log-index = slave-relay-bin.index //增加
这里要注意 server-id 不能相同。
需要删除字符集utf8的语句
5.master、slave1、slave2 分别做两个软链接,软链接是为 HMA 服务的。
[root@Mysql1 ~]# ln -s /usr/local/mysql/bin/mysql /usr/sbin/
[root@Mysql1 ~]# ln -s /usr/local/mysql/bin/mysqlbinlog /usr/sbin/
6.master、slave1、slave2 启动 MySQL。
[root@Mysql1 ~]# systemctl start mysqld
[root@Mysql1 ~]# systemctl status mysqld
[root@Mysql1 ~]# netstat -anpt | grep 3306
7.配置 MySQL 一主两从
MySQL 主从配置相对比较简单。需要注意的是授权。步骤如下:
[root@master ~]# mysql
mysql> grant replication slave on *.* to 'myslave'@'192.168.10.%' identified by '123';
mysql> grant all privileges on *.* to 'mha'@'192.168.10.%' identified by 'manager';
mysql> flush privileges;
mysql> grant all privileges on *.* to 'mha'@'Mysql1' identified by 'manager';
mysql> grant all privileges on *.* to 'mha'@'Mysql2' identified by 'manager';
mysql> grant all privileges on *.* to 'mha'@'Mysql3' identified by 'manager';
mysql> show master status
-> ;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 1295 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
mysql> change master to master_host='192.168.10.10',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=1295; 和上表保持一致
mysql> start slave;
mysql> show slave status\G;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
##I/O线程显示为NO: 主库与从库网络不通、主库未授权给从库
##SQL线程显示为NO:从库日志和位置点与主不同步
##若从库查看连接主库I/0线程状态为conneting,一直是这个状态,考虑双方的防火墙是否开启。
6.必须设置两个从库为只读模式
mysql> set global read_only=1;
7.在主库插入两条数据,测试是否同步
mysql> create database qi;
mysql> use tanwenlong;
mysql> create table test(id int(4));
mysql> insert into test(id) values (1);
mysql> show tables;
+--------------+
| Tables_in_qi |
+--------------+
| test |
+--------------+
1 row in set (0.00 sec)
8.在两个从库分别查询如下所示说明主从同步正常
mysql> select * from qi.test;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
1、在所有服务器上都安装 MHA 依赖的环境,每个服务器上都需要两个源(epel.repo和CentOS7-Base-163.repo),将这两个源放入/etc/yum.repos.d的目录下,在主服务器上操作演示安装
[root@manger ~]# yum install epel-release --nogpgcheck
[root@manger ~]# yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker perl-CPAN
2、在所有服务器上必须先安装 node 组件,最后在 MHA-manager 节点上安装 manager 组件,因为 manager 依赖 node 组件
[root@manger ~]# tar zxvf mha4mysql-node-0.57.tar.gz
[root@manger ~]# cd mha4mysql-node-0.57/
[root@manger mha4mysql-node-0.57]# perl Makefile.PL
[root@manger mha4mysql-node-0.57]# make && make install
3、在mha-manager 服务器上安装 manager 组件
[root@manger ~]# tar zxvf mha4mysql-manager-0.57.tar.gz
[root@manger ~]# cd mha4mysql-manager-0.57/
[root@manger mha4mysql-manager-0.57]# perl Makefile.PL
[root@manger mha4mysql-manager-0.57]# make && make install
工具 | 作用 |
---|---|
masterha_check_ssh | 检查 MHA 的 SSH 配置状况 |
masterha_check_repl | 检查 MySQL 复制状况 |
masterha_manger | 启动 manager的脚本 |
masterha_check_status | 检测当前 MHA 运行状态 |
masterha_master_monitor | 检测 master 是否宕机 |
masterha_master_switch | 控制故障转移(自动或者手动) |
masterha_conf_host | 添加或删除配置的 server 信息 |
masterha_stop | 关闭manager |
脚本 | 作用 |
---|---|
save_binary_logs | 保存和复制 master 的二进制日志 |
apply_diff_relay_logs | 识别差异的中继日志事件并将其差异的事件应用于其他的 slave |
filter_mysqlbinlog | 去除不必要的 ROLLBACK 事件(MHA 已不再使用这个工具) |
purge_relay_logs | 清除中继日志(不会阻塞 SQL 线程) |
4.配置无密码认证
manger服务器
[root@manger ~]# ssh-keygen -t rsa
[root@manger ~]# ssh-copy-id 192.168.10.10
[root@manger ~]# ssh-copy-id 192.168.10.20
[root@manger ~]# ssh-copy-id 192.168.10.30
master
[root@master ~]# ssh-keygen -t rsa
[root@master ~]# ssh-copy-id 192.168.10.20
[root@master ~]# ssh-copy-id 192.168.10.30
slave1:
[root@slave1 ~]# ssh-keygen -t rsa
[root@slave1 ~]# ssh-copy-id 192.168.10.10
[root@slave1 ~]# ssh-copy-id 192.168.10.30
slave2:
[root@slave2 ~]# ssh-keygen -t rsa
[root@slave2 ~]# ssh-copy-id 192.168.10.10
[root@slave2 ~]# ssh-copy-id 192.168.10.20
1.在 manager 节点上复制相关脚本到/usr/local/bin 目录,复制上述的自动切换时 VIP 管理的脚本到/usr/local/bin 目录,这里使用脚本管理 VIP
[root@manger ~]# cp -ra mha4mysql-manager-0.57/samples/scripts /usr/local/bin/
[root@manger ~]# ll /usr/local/bin/scripts/
总用量 32
-rwxr-xr-x. 1 1001 1001 3648 5月 31 2015 master_ip_failover ##自动切换时 VIP 管理的脚本
-rwxr-xr-x. 1 1001 1001 9870 5月 31 2015 master_ip_online_change ##在线切换时 vip 的管理
-rwxr-xr-x. 1 1001 1001 11867 5月 31 2015 power_manager ## 故障发生后关闭主机的脚本
-rwxr-xr-x. 1 1001 1001 1360 5月 31 2015 send_report ## 因故障切换后发送报警的脚本
[root@manger ~]# cp /usr/local/bin/scripts/master_ip_failover /usr/local/bin/
[root@manger ~]# vi /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 = '192.168.10.200';
my $brdc = '192.168.10.255';
my $ifdev = 'ens33';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down";
my $exit_code = 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";
}
2.创建 MHA 软件目录并拷贝配置文件
[root@manger ~]# mkdir /etc/masterha
[root@manger ~]# cp mha4mysql-manager-0.57/samples/conf/app1.cnf /etc/masterha/
[root@manger ~]# vi /etc/masterha/app1.cnf
[server default]
manager_workdir=/var/log/masterha/app1
manager_log=/var/log/masterha/app1/manager.log
master_binlog_dir=/usr/local/mysql/data
master_ip_failover_script= /usr/local/bin/master_ip_failover
master_ip_online_change_script= /usr/local/bin/master_ip_online_change
password=manager
user=mha
ping_interval=1
remote_workdir=/tmp
repl_password=123456
repl_user=myslave
secondary_check_script= /usr/local/bin/masterha_secondary_check -s 192.168.10.10 -s 192.168.10.20 -s 192.168.10.30
shutdown_script=""
ssh_user=root
[server1]
hostname=192.168.10.10
port=3306
[server2]
hostname=192.168.10.20
port=3306
candidate_master=1 #设置为候选master
check_repl_delay=0 #默认情况下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slave作为一个新的slave,但check_repl_delay=0的话,即使落后很多日志,也强制选择其为备选主库。
[server3]
hostname=192.168.10.30
port=3306
3.测试 ssh 无密码认证,如果正常最后会输出 successfully
[root@manger ~]# masterha_check_ssh --conf=/etc/masterha/app1.cnf
。。。此处省略
Wed Dec 30 16:48:49 2020 - [info] All SSH connection tests passed successfully.
4、测试 MySQL 主从连接情况,最后出现 MySQL Replication Health is OK 字样说明正常
[root@manger ~]# masterha_check_repl -conf=/etc/masterha/app1.cnf
............... #省略内容
IN SCRIPT TEST====/sbin/ifconfig ens33:1 down==/sbin/ifconfig ens33:1 20.0.0.200===
Checking the Status of the script.. OK
Sun Nov 1 15:54:59 2020 - [info] OK.
Sun Nov 1 15:54:59 2020 - [warning] shutdown_script is not defined.
Sun Nov 1 15:54:59 2020 - [info] Got exit code 0 (Not master dead).
MySQL Replication Health is OK.
5.第一次配置需要去master上手动开启虚拟IP
[root@master ~]# /sbin/ifconfig ens33:1 192.168.10.100/24
6.启动MHA
[root@manger ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/masterha/app1/manager.log 2>&1 &
7.查看 MHA 状态,可以看到当前的 master 是主服务器节点
[root@manger ~]# masterha_check_status --conf=/etc/masterha/app1.cnf
app1 (pid:5692) is running(0:PING_OK), master:192.168.10.10
8.查看 MHA 日志,也以看到当前的 master 是 192.168.10.10
cat /var/log/masterha/app1/manager.log
1、将master数据库关闭,模拟宕机
[root@master ~]# pkill -9 mysql
2、查看从库slave2状态,master_host有原slave1顶替,IO进程和SQL进程正常
[root@slave2 ~]# mysql
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.10.20 ###主库成功切换到备选主库
Master_User: myslave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 1232
Relay_Log_File: relay-log-bin.000002
Relay_Log_Pos: 284
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
在slave1上用ip addr查看漂移地址vip
[root@slave1 ~]# ip addr
ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:32:ee:41 brd ff:ff:ff:ff:ff:ff
inet 192.168.10.20/24 brd 192.168.10.255 scope global ens33
valid_lft forever preferred_lft forever
inet 192.168.10.200/24 brd 192.168.10.255 scope global secondary ens33:1
[root@manger ~]# vi /etc/masterha/app1.cnf
。。。此处省略
[server1]
hostname=192.168.10.10
port=3306
candidate_master=1
check_repl_delay=0
[server2]
hostname=192.168.10.20
port=3306
[server3]
hostname=192.168.10.30
port=3306
1.在master服务器上重启mysql服务,将坏库重新添加到主从同步中
[root@master ~]# systemctl start mysql
[root@master ~]# mysql
mysql> change master to master_host='192.168.10.20',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=1892;
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.10.20
Master_User: myslave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 1232
Relay_Log_File: master-relay-bin.000002
Relay_Log_Pos: 284
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
2.测试主从同步是否正常:
主服务器
mysql> create database qi2;
Query OK, 1 row affected (0.00 sec)
从服务器
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| qi |
| qi2 |
| t1 |
| test |
+--------------------+
7 rows in set (0.00 sec)
3.健康检查
[root@Manager ~]# masterha_check_ssh -conf=/etc/masterha/app1.cnf
[root@Manager ~]# masterha_check_repl -conf=/etc/masterha/app1.cnf
...省略内容
MySQL Replication Health is OK.
4.启动服务
[root@manager ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/masterha/app1/manager.log 2>&1 &
Slave_IO_Running: NO
Slave_IO_Running: Connecting
Slave_SQL_Running: NO
masterha_check_ssh -conf=/etc/masterha/app1.cnf
masterha_check_repl -conf=/etc/masterha/app1.cnf
grant all privileges on *.* to 'mha'@'192.168.158.10' identified by 'manager';
grant all privileges on *.* to 'mha'@1'92.168.158.20' identified by 'manager';
grant all privileges on *.* to 'mha'@'192.168.158.30' identified by 'manager';
若出现There is no alive slave.We can’t do failover.
请显示着关闭从防火墙!!!