MySQL集群MHA
MHA由两部分构成:MHA Manager(管理节点)和MHA Node(数据节点)。在主从复制的MySQL集群中,MHA Manager负责监控主节点的健康状况,当主节点出现故障时,MHA Manager会自动选举出一个从节点升级为主节点,并协调其余从节点重新连接至新的主节点,实现无缝的故障转移。
监控与故障检测:MHA Manager通过心跳检测机制实时监控主节点状态,一旦检测到主节点失效,立即触发故障转移流程。
自动故障转移:基于预定义的故障转移策略,如优先级、数据延迟等指标,MHA会选择一个符合条件的从节点晋升为主节点。
数据一致性保证:MHA支持半同步复制和全局事务ID(GTID)复制,以确保故障转移前后数据的一致性。
MHA 之所以存在,是为了帮助解决主从复制中的数据不一致问题,特别是在主库发生故障时。
MHA工作原理
相对比其它HA软件,MHA的目的在于维持MySQL Replication中Master库的高可用性,其最大特点是可以修复多个Slave之间的差异日志,最终使所有Slave保持数据一致,然后从中选择一个充当新的Master,并将其它Slave指向它。
- 从宕机崩溃的master保存二进制日志事件(binlog events);
- 识别含有最新更新的slave;
- 应用差异的中继日志(relay log)到其他的slave;
- 应用从master保存的二进制日志事件(binlog events);
- 提升一个slave为新的master;
- 使其他的slave连接新的master进行复制;
MHA同步方式
同步复制:主库在接收到写请求后,会等待所有的从服务器同步完毕之后,才会返回给客户端
异步复制:MySQL主从复制默认采用异步复制方式,主库在接收到写请求后立即返回,无需等待从库确认,这种方式响应速度快,但可能存在一定的数据延迟
半同步复制:至少有一个从库接收到并执行完写操作后,主库才返回成功,提高了数据一致性。
管理节点与数据节点
MHA Manager(管理节点)
MHA Manager是一个中心化的管理组件,通常部署在独立的服务器上,不直接处理数据库的读写请求。
它的主要职责是监控整个MySQL主从集群的健康状态,包括检测主节点是否在线、从节点的复制延迟等。
当主节点出现故障时,MHA Manager会自动执行故障转移流程,选择一个从节点升级为主节点,同时通知其他从节点改变复制源至新的主节点,并确保数据一致性。
MHA Manager还负责处理各种高级特性,比如半同步复制的管理、全局事务标识符(GTID)的支持、以及故障转移过程中的SQL线程暂停和恢复等。
MHA Node(数据节点)
MHA Node指的是参与MySQL主从复制集群中的所有数据库服务器,包括原来的主节点和从节点。
每个MHA Node都运行着MHA的Node Agent,用于与MHA Manager通信,报告自身状态和接收管理指令。
主节点主要负责处理写入请求和生成二进制日志,而从节点则通过复制主节点的二进制日志来保持数据同步,并在必要时准备晋升为主节点。
mha环境部署
注意事项:
mha的master节点不能使用centos8
部署流程
1.搭建主从集群
MHA master节点 | centos7 192.168.5.105 |
主数据库节点 | centos8 192.168.5.101 |
从节点1 | centos8 192.168.5.102 |
从节点2 | centos8 192.168.5.103 |
1.1 数据库集群修改配置文件(三台主机配置文件相同,server-id不同)
[root@server1 ~]# cat /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/data/mysql/data
port=3306
socket=/usr/local/mysql/mysql.sock
symbolic-links=0
character-set-server=utf8
log-error=/data/mysql/log/mysqld.log
pid-file=/usr/local/mysql/mysqld.pid
log-bin=/data/mysql/log/mysql_bin
server-id=1
log-slave-updates=1
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=10000
rpl_semi_sync_slave_enabled=1
rpl_semi_sync_master_enabled=1
启用主库的半同步复制功能。
当此参数设置为 1 时,主库 会启用半同步复制模式。在这种模式下,主库会在提交事务时等待至少一个从库确认接收到该事务(即从库向主库发送一个确认信号)。
如果设置为 0,则半同步复制会被禁用,主库在提交事务时不会等待从库确认,而是直接提交。
rpl_semi_sync_master_timeout=10000
当此参数设置为 10000(即 10 秒)时,主库在提交事务后,最多等待 10 秒钟,直到至少一个从库确认接收到该事务。如果在 10 秒内没有接收到确认,主库将继续执行后续操作,可能会丢失对该事务的等待(如果 rpl_semi_sync_master_enabled 为 1)。
如果设置为 0,则表示没有超时,主库将一直等待从库的确认。
rpl_semi_sync_slave_enabled=1
当此参数设置为 1 时,从库 会启用半同步复制模式。此时,从库在接收到主库的事务并成功写入后,会向主库发送确认信号,表明事务已接收到并准备执行。
如果设置为 0,则从库将只进行异步复制,不会向主库发送确认信号。
log-slave-updates=1
log-slave-updates 是一个从库配置项,用于控制从库是否将其接收到的复制事务(即从主库复制来的事务)记录到从库的 binlog 中。
当该选项设置为 1 时,表示 从库 会将它从主库接收到的所有更新(包括 INSERT、UPDATE、DELETE 等)记录到它自己的二进制日志 (binlog) 中。
这意味着,从库可以充当其他从库的主库,从而形成 链式复制(relay replication)。如果没有启用该选项,则从库仅仅是作为一个数据副本,不会生成新的 binlog,也无法向其他从库提供数据。
relay_log_purge=0
relay_log_purge 是一个从库配置项,用于控制是否自动清理已经执行过的中继日志(relay_log)。relay_log 是从库用来存储从主库接收到的复制事务的日志文件。
当 relay_log_purge=0 时,表示 禁用自动清理中继日志。
1.2 创建用户并授权(集群所有机器执行)
grant replication slave on *.* to slave@'192.168.1.%' identified by '123456';
grant all privileges on *.* to root@"192.168.1.%" identified by '123456';
刷新生效
mysql> flush privileges;
MHA 需要能够 远程访问 MySQL 实例(包括主库和从库)
1.3 从节点修改slave状态(两台从节点上执行)
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to master_host='192.168.5.101',master_user='slave',master_password='123456',master_log_file='mysql_bin.000001',master_log_pos=4;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
结合半同步搭建MHA
2.1基础环境部署
配置hosts和ssh互信
[root@server1 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.5.101 server1
192.168.5.102 server2
192.168.5.103 server3
192.168.5.104 centos7
[root@server1 ~]# for i in 1 2 3 5; do scp /etc/hosts root@192.168.5.10$i:/etc/hosts ;done
[root@centos7 ~]# for i in 1 2 3 5; do ssh root@192.168.5.10$i "ssh-keygen" ;done
[root@server1 ~]# for i in 1 2 3 5;do ssh-copy-id 192.168.5.10$i ;done
[root@server2 ~]# for i in 1 2 3 5;do ssh-copy-id 192.168.5.10$i ;done
[root@server3 ~]# for i in 1 2 3 5;do ssh-copy-id 192.168.5.10$i ;done
[root@centos7 ~]# for i in 1 2 3 5;do ssh-copy-id 192.168.5.10$i ;done
配置yum源
配置Centos8节点epel源和yum源
rm -rf /etc/yum.repos.d/*
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo
sed -i 's/mirrors.cloud.aliyuncs.com/mirrors.aliyun.com/g' /etc/yum.repos.d/CentOS-Base.repo
sed -i 's/\$releasever/\$releasever-stream/g' /etc/yum.repos.d/CentOS-Base.repo
yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm
sed -i 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*
配置centos7yum和epel源
rm -rf /etc/yum.repos.d/*
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum install -y epel-release
2.2上传mha组件包,将node包传到从节点
所有节点上安装
yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager --skip-broken --nogpgcheck
rpm -ivh mha4mysql-node-0.57-0.el7.noarch.rpm
Centos7(master节点)安装
yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager --skip-broken --nogpgcheck;rpm -ivh mha4mysql-node-0.57-0.el7.noarch.rpm
yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker perl-CPAN
[root@centos7 ~]# rpm -ivh mha4mysql-manager-0.57-0.el7.noarch.rpm
[root@centos7 ~]# ll /usr/bin/master*
-rwxr-xr-x 1 root root 1995 May 31 2015 /usr/bin/masterha_check_repl
-rwxr-xr-x 1 root root 1779 May 31 2015 /usr/bin/masterha_check_ssh
-rwxr-xr-x 1 root root 1865 May 31 2015 /usr/bin/masterha_check_status
-rwxr-xr-x 1 root root 3201 May 31 2015 /usr/bin/masterha_conf_host
-rwxr-xr-x 1 root root 2517 May 31 2015 /usr/bin/masterha_manager
-rwxr-xr-x 1 root root 2165 May 31 2015 /usr/bin/masterha_master_monitor
-rwxr-xr-x 1 root root 2373 May 31 2015 /usr/bin/masterha_master_switch
-rwxr-xr-x 1 root root 5171 May 31 2015 /usr/bin/masterha_secondary_check
-rwxr-xr-x 1 root root 1739 May 31 2015 /usr/bin/masterha_stop
安装插件
查看半同步信息
mysql> show variables like '%have_dynamic%';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| have_dynamic_loading | YES |
+----------------------+-------+
1 row in set (0.00 sec)
mysql> show variables like '%plugin_dir%';
+---------------+------------------------------+
| Variable_name | Value |
+---------------+------------------------------+
| plugin_dir | /usr/local/mysql/lib/plugin/ |
+---------------+------------------------------+
1 row in set (0.01 sec)
have_dynamic_loading = YES 表示 MySQL 支持动态加载插件。
plugin_dir = /usr/local/mysql/lib/plugin/ 指定了插件存放的目录位置。
mysql半同步插件是由谷歌提供,具体位置/usr/local/mysql/lib/plugin/下,一个是master用的semisync_master.so,一个是slave用的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'
查看是否安装成功
[root@server1 ~]# mysql -e 'show plugins;' | grep rpl_semi*
rpl_semi_sync_master ACTIVE REPLICATION semisync_master.so GPL
rpl_semi_sync_slave ACTIVE REPLICATION semisync_slave.so GPL
查看半同步状态信息
mysql> show status like '%rpl_semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 2 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 12 |
| 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 | 1114 |
| Rpl_semi_sync_master_tx_wait_time | 6689 |
| Rpl_semi_sync_master_tx_waits | 6 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 6 |
| Rpl_semi_sync_slave_status | OFF |
+--------------------------------------------+-------+
15 rows in set (0.00 sec)
Rpl_semi_sync_master_clients
含义: 当前连接到主服务器并支持半同步复制的从服务器数量。这里显示有 2 个从服务器支持半同步复制。
配置MHA master节点
新建配置文件
mkdir /etc/mhamaster
mkdir /var/log/masterha/app1
[root@centos7 ~]# cat /etc/mhamaster/mha.conf
[server default]
manager_log=/var/log/masterha/app1/manager.log
manager_workdir=/var/log/masterha/app1
master_binlog_dir=/data/mysql/log
password=123456
ping_interval=1
remote_workdir=/tmp
repl_password=123456
repl_user=slave
report_script=/usr/local/send_report
shutdown_script=""
ssh_user=root
user=root
[server1]
hostname=192.168.5.101
port=3306
[server2]
hostname=192.168.5.102
port=3306
[server3]
hostname=192.168.5.103
port=3306
配置文件解释
[server default]
manager_workdir=/var/log/masterha/app1 #设置manager的工作目录
manager_log=/var/log/masterha/app1/manager.log #设置manager的日志
master_binlog_dir=/data/mysql/log #设置master 保存binlog的位置,以便MHA可以找到master的日志,我这里的也就是mysql的数据目录,注:所有mysql的binlog文件路径都要与该路径一致。
#master_ip_failover_script=/usr/bin/master_ip_failover #设置自动故障切换时候的脚本
master_ip_online_change_script=/usr/bin/master_ip_online_change #设置手动切换时候的切换脚本
user=root #设置监控用户manager
password=123456 #监控用户manager的密码
ping_interval=1 #设置监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应的时候自动进行failover(故障切换)
remote_workdir=/tmp #设置远端mysql在发生切换时binlog的保存位置
repl_user=slave #设置复制环境中的复制用户名
repl_password=123456 #设置复制用户的密码
report_script=/usr/local/send_report #设置发生切换后发送的报警的脚本
shutdown_script="" #设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机防止发生脑裂,这里没有使用)
ssh_user=root #设置ssh的登录用户名
[server1]
hostname=192.168.1.11
port=3306
#candidate_master=1
[server2]
hostname=192.168.1.12
port=3306
#candidate_master=1 #设置为候选master,如果设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的slave
#check_repl_delay=0 #默认情况下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slave作为一个新的master,因为对于这个slave的恢复需要花费很长时间,通过设置check_repl_delay=0,MHA触发切换在选择一个新的master的时候将会忽略复制延时,这个参数对于设置了candidate_master=1的主机非常有用,因为这个候选主在切换的过程中一定是新的master
[server3]
hostname=192.168.1.13
port=3306
检查ssh配置和主从复制情况
masterha_check_ssh --conf=/etc/masterha/app1.cnf masterha_check_repl --conf=/etc/masterha/app1.cnf
查看MHA Manager的状态
masterha_check_status --conf=/etc/masterha/app1.cnf
开启MHA Manager监控
nohup masterha_manager --conf=/etc/masterha/mha.conf \ --remove_dead_master_conf --ignore_last_failover < /dev/null > \ /var/log/masterha/app1/manager.log 2>&1 &
masterha_manager --conf
/var/log/masterha/app1/manager.log
这里目录需要改成环境配置的目录
配置VIP配合MHA使用
生成虚拟vip
ifconfig ens160:1 192.168.5.66 netmask 255.255.255.0 up
在MHAmaster节点上修改配置文件
[root@centos7 ~]# vim /etc/mhamaster/mha.conf
master_ip_failover_script=/usr/bin/master_ip_failover #设置自动故障切换时候的脚本
创建vip脚本
vim /usr/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.5.66/24';
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";
#`ssh $ssh_user\@cluster1 \" $ssh_start_vip \"`;
exit 0;
}
else {
&usage();
exit 1;
}
}
# A simple system call that enable the VIP on the new master
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";
}
脚本解释
导入的模块和变量声明
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
#strict: 启用严格模式,要求变量声明必须明确,这有助于避免一些常见的错误。
#warnings: 启用警告模式,FATAL => 'all' 意味着如果有任何警告,脚本会终止执行。
#Getopt::Long: 用来处理命令行选项。它使得可以使用长格式的命令行参数(例如 --command=start)。
------------------------------------------------------------------------------------------------------------
变量声明
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.1.66/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down";
$vip: 定义了要迁移的虚拟 IP 地址和子网掩码。
$key: 用于虚拟接口的标识符(假设这是一个附加到 ens33 网卡的虚拟接口)。
$ssh_start_vip 和 $ssh_stop_vip: 这两行是通过 SSH 命令在远程主机上启动或停止 VIP。ens33:$key 代表的是虚拟网卡接口。
------------------------------------------------------------------------------------------------------------
GetOptions(获取命令行参数)
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,
);
--command: 指定操作类型(start、stop、stopssh、status)。
--ssh_user: SSH 用户名。
--orig_master_host, --orig_master_ip, --orig_master_port: 原主机的相关信息。
--new_master_host, --new_master_ip, --new_master_port: 新主机的相关信息。
------------------------------------------------------------------------------------------------------------
主程序逻辑(main 函数)
sub main {
print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
在 main 函数的开始,它打印了一些调试信息,包括启动和停止 VIP 的命令。
根据 command 参数的不同,脚本会执行不同的操作:、
stop 或 stopssh 操作
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;
}
如果命令是 stop 或 stopssh,脚本会尝试停止原主机上的 VIP。
通过调用 stop_vip 函数来关闭 VIP。
如果发生错误,捕获异常(eval)并打印错误信息,最后根据是否有错误设置退出码。
start 操作
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;
}
如果命令是 start,脚本会尝试启动新主机上的 VIP。
通过调用 start_vip 函数来启用 VIP。
同样,捕获任何错误并设置退出码。
status 操作
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";
exit 0;
}
如果命令是 status,脚本仅输出一条状态信息并退出。
如果输入的命令不是 start、stop 或 status,则显示使用说明并退出。
------------------------------------------------------------------------------------------------------------
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 \"`;
}
该函数通过 SSH 执行命令,在新主机上启用或禁止vip
总结:
搭建:
- 主从架构创建同步用户和创建mha登录用户(创建两个用户)
- MHA管理工具node所有节点分发。manager节点工具检查集群状态使用。
- MHA的配置文件
- VIP管理脚本
通过心跳检测服务是否宕机、发现服务宕机后通过ssh进入读取最新的binlog日志保存。发送给有最新数据的slave节点进行数据同步。将新的slave节点升级为新的主节点。其他slave节点指向新的master节点。结合vip使用,app连接过程数据库宕机不用更换ip地址。通过vip管理脚本,vip自动漂移至新的master节点上。
标签:MHA,vip,master,ssh,MySQL,集群,root,节点 From: https://www.cnblogs.com/cloudwangsa/p/18637859