当前位置: 首页 > news >正文

MySQL高可用之MHA

华子目录

  • `MHA`概述
  • 为什么要用`MHA`
  • 什么是`MHA`
  • `MHA`的组成
  • `MHA`的特点
    • 故障切换备选主库的算法
  • `MHA`工作原理
  • `MHA`环境搭建
    • 环境准备
    • 开始部署`MHA`
    • `MHA软件`使用介绍
    • 配置`MHA`的`管理环境`
      • 创建`MHA管理`的`模板文件`
    • 测试
  • 模拟故障`MySQL-master`切换
    • `手动切换`(在`master`存活状态下`切换`)
    • `手动切换`(在`master`死亡状态下`切换`)
    • `自动切换`
  • `MHA`的`故障切换过程`
  • 为`MHA`添加`vip功能`
    • 测试1(`自动故障切换`)
    • 测试2 (通过`vip`登录`数据库`)

MHA概述

在这里插入图片描述

为什么要用MHA

  • 解决MySQL集群中master单点故障问题

什么是MHA

  • MHAMaster High Availability)是一套优秀MySQL高可用环境下故障切换主从复制软件
  • MHA的出现就是解决MySQL 中master单点故障问题
  • MySQL故障切换过程中,MHA能做到0-30秒内自动完成故障切换操作
  • MHA能在故障切换的过程中最大程度上保证数据一致性,以达到真正意义上的高可用

MHA的组成

  • MHA两部分组成:MHA Manager (管理节点) MHA Node (数据库节点)
  • MHA Manager可以单独部署在一台独立的机器管理多个master-slave集群,也可以部署在一台slave节点上(MHA独立出来一台主机,只能在企业7中做)
  • MHA Manager会定时探测集群中的master节点
  • master出现故障时,它可以自动最新数据slave提升为master,然后将所有其他的slave 重新指向master
  • MHA-master是可以是一台单独服务器nodeMySQL服务器(包括mysql-master,mysql-slave)

MHA的特点

  • 自动故障切换过程中,MHA宕机主服务器上保存二进制日志最大程度保证数据不丢失
  • 使用半同步复制,可以大大降低数据丢失的风险,如果只有一个slave已经收到了最新二进制日志MHA可以将最新二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点数据一致性
  • 目前MHA支持一主多从架构,最少三台服务,即一主两从

故障切换备选主库的算法

  • 一般判断从库的是position/gtid)判断优劣,数据有差异,最接近于masterslave,成为备选
  • 数据一致情况下,按照配置文件顺序,选择备选主库
  • 设定有权重candidate_master=1),按照权重强制指定备选
    • 默认情况下如果一个slave落后master 100Mrelay logs,即使有权重,也会失效
    • 如果check_repl_delay=0,即使落后很多日志,也强制选择其为备选

MHA工作原理

  • 目前MHA主要支持一主多从架构,要搭建MHA,要求一个复制集群必须最少3台数据库服务器一主二从,即一台充当Master一台充当备用Master另一台充当从库
  • MHA Node运行在每台MySQL服务器
  • MHA Manager会定时探测集群中的master节点
  • master出现故障时,它可以自动将最新数据slave提升为master
  • 然后将所有其他的slave重新指向masterVIP自动漂移master
  • 整个故障转移过程对应用程序完全透明

MHA环境搭建

环境准备

  • 准备一台MHA主机ip172.25.254.50/24主机名mha.org

在这里插入图片描述

  • hosts解析
[root@mha ~]# vim /etc/hosts

在这里插入图片描述

[root@mysql-node1 ~]# vim /etc/hosts

在这里插入图片描述

[root@mysql-node2 ~]# vim /etc/hosts

在这里插入图片描述

[root@mysql-node3 ~]# vim /etc/hosts

在这里插入图片描述

  • mhanode1,node2,node3之间做免密认证
#mha制作公私钥
[root@mha ~]# ssh-keygen -t rsa
#将mha的公钥传给node1,node2,node3
[root@mha ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.25.254.10[root@mha ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.25.254.20[root@mha ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.25.254.30
#此时免密登录完成
  • 修改node1,node2,node3中的/etc/my.cnf文件
    • 实验要求node1masternode2备用masternode3slave
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=10
log-bin=master-bin  #开启binlog
gtid_mode=ON
enforce-gtid-consistency=ON
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=10
log-bin=master-bin  #开启binlog
gtid_mode=ON
enforce-gtid-consistency=ON
[root@mysql-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=30
gtid_mode=ON
enforce-gtid-consistency=ON

因为node2可能会成为master,所以,node2开启binlog功能。由于node3slave不会被选举为master,所以不用开启binlog

  • node1,node2,node3重新部署MySQL
[root@mysql-node1 ~]# /etc/init.d/mysqld stop[root@mysql-node1 ~]# rm -rf /data/mysql/*[root@mysql-node1 ~]# mysqld --user=mysql --initialize[root@mysql-node1 ~]# mysql -uroot -p'p5Y0jI%DMp9h'mysql> alter user root@localhost identified by "123456";

node2,node3同上

  • node1上建立数据同步用户并进行主从复制授权,并开启半同步模式
#node1上建立同步用户
mysql> create user huazi@'%' identified by "123456";
#授权
mysql> grant replication slave on *.* to huazi@'%';
#半同步设置
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';#开启半同步
mysql> set global rpl_semi_sync_master_enabled=1;mysql> show master status\G;

在这里插入图片描述

#node2
mysql> change master to \-> master_host='172.25.254.10',-> master_user='huazi',-> master_password='123456',-> master_auto_position=1;mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';mysql> set global rpl_semi_sync_slave_enabled=1;mysql> start slave;mysql> show slave status\G;

在这里插入图片描述

#node3上
mysql> change master to \-> master_host='172.25.254.10',-> master_user='huazi',-> master_password='123456',-> master_auto_position=1;mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';mysql> set global rpl_semi_sync_slave_enabled=1;mysql> start slave;mysql> show slave status\G;

在这里插入图片描述

  • MySQL-master备用master上创建登录用户
#node1上
mysql> create user root@'%' identified by "123456";mysql> grant all on *.* to root@'%';

由于主从复制,我们在node1上的创建了登录用户node2上也自然会同步到

#node上
mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| huazi         | %         |
| root          | %         |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+#node2上
mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| huazi         | %         |
| root          | %         |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+#node3上
mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| huazi         | %         |
| root          | %         |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+

开始部署MHA

  • 上传MHA包mha.org主机

在这里插入图片描述

  • 解压
[root@mha ~]# unzip MHA-7.zip
[root@mha ~]# cd MHA-7/
[root@mha MHA-7]# ls
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
mha4mysql-manager-0.58.tar.gz
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
perl-Config-Tiny-2.14-7.el7.noarch.rpm
perl-Email-Date-Format-1.002-15.el7.noarch.rpm
perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
perl-MIME-Lite-3.030-1.el7.noarch.rpm
perl-MIME-Types-1.38-2.el7.noarch.rpm
perl-Net-Telnet-3.03-19.el7.noarch.rpm
perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm
  • 安装
[root@mha MHA-7]# yum install *.rpm -y
  • mha4mysql-node-0.58-0.el7.centos.noarch.rpm包发送给所有mysql服务器
[root@mha MHA-7]# rsync mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.254.10:/root/[root@mha MHA-7]# rsync mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.254.20:/root/[root@mha MHA-7]# rsync mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.254.30:/root/
  • node1,node2,node3安装mha4mysql-node-0.58-0.el7.centos.noarch.rpm
#node1上安装
[root@mysql-node1 ~]# yum install mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y
#node2上安装
[root@mysql-node2 ~]# yum install mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y
#node3上安装
[root@mysql-node3 ~]# yum install mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y

MHA软件使用介绍

manager工具包主要包括以下几个工具

  • masterha_check_ssh 检查MHA的ssh配置状况
  • masterha_check_repl 检查MySQL复制状况
  • masterha_manger 启动MHA,进行监控MySQL-master的状态
  • masterha_check_status 检查当前MHA运行状态
  • masterha_master_monitor 检查master是否宕机
  • masterha_master_switch 手动切换MySQL-master
  • masterha_conf_host 添加或删除配置的server信息

node工具包(通常由MHA主机直接调用,无需人为执行

  • save_binary_logs 保存和复制master的二进制日志
  • apply_diff_relay_logs 识别差异中的中继日志事件并将其差异的事件应用于其他的slave
  • filter_mysqlbinlog 去除不必要的rollback事件(MHA已不再使用这个工具)
  • purge_relay_logs 清除中继日志(不会阻塞sql线程)

配置MHA管理环境

#创建MHA配置文件存储位置
[root@mha ~]# mkdir /etc/masterha/
[root@mha ~]# masterha_manager --help
Usage:masterha_manager --global_conf=/etc/masterha_default.cnf--conf=/usr/local/masterha/conf/app1.cnfSee online reference(http://code.google.com/p/mysql-master-ha/wiki/masterha_manager) fordetails.
  • --global-confMHA的全局配置文件记录公共设定
  • --confMHA的子配置文件,不同管理配置文件,记录各自配置

创建MHA管理模板文件

[root@mha MHA-7]# tar -zxf mha4mysql-manager-0.58.tar.gz[root@mha MHA-7]# cd mha4mysql-manager-0.58/[root@mha mha4mysql-manager-0.58]# ls -F
AUTHORS  COPYING  lib/          MANIFEST       README  samples/  tests/
bin/     debian/  Makefile.PL*  MANIFEST.SKIP  rpm/    t/[root@mha mha4mysql-manager-0.58]# cd samples/
[root@mha samples]# ls
conf  scripts
[root@mha samples]# cd conf/
[root@mha conf]# ls
app1.cnf  masterha_default.cnf#将两个文件中的内容合并为一个文件,并写到/etc/masterha/app1.conf文件中
[root@mha conf]# cat masterha_default.cnf app1.cnf > /etc/masterha/app1.conf
  • 修改app1.conf内容
[root@mha conf]# cd /etc/masterha/
[server default]
user=root  #MySQL中用于登录的用户
password=123456  #用户密码
ssh_user=root  #node1,node2,node3中用户ssh登录的用户
repl_user=huazi  #MySQL用户数据同步的用户
repl_password=123456  #用户密码
master_binlog_dir= /data/mysql   #主库二进制日志的存储目录
remote_workdir=/tmp   #在远程服务器上执行命令时的工作目录
secondary_check_script= masterha_secondary_check -s 172.25.254.10 -s 172.25.254.11  #此参数使为了提供冗余检测,方式是mha主机网络自身的问题无法连接数据库节点,第二个应为集群之外的主机
ping_interval=3    #MHA Manager检测从库存活状态的间隔(秒)
# master_ip_failover_script= /script/masterha/master_ip_failover  #发生故障后调用的脚本,用来迁移vip
# shutdown_script= /script/masterha/power_manager  #电源管理脚本
# report_script= /script/masterha/send_report  #当发生故障后用此脚本发邮件或者告警通知
# master_ip_online_change_script= /script/masterha/master_ip_online_change  #在线切换时调用的vip迁移脚本,手动
[server default]
manager_workdir=/etc/masterha   #MHA-master的工作目录
manager_log=/etc/masterha/manager.log  #MHA Manager的日志文件路径[server1]
hostname=172.25.254.10
candidate_master=1    #表示该服务器可以作为候选主库
check_repl_delay=0   #复制延迟检查阈值,0表示不进行延迟检查[server2]
hostname=172.25.254.20
candidate_master=1   #表示该服务器可以作为候选主库
check_repl_delay=0   #复制延迟检查阈值,0表示不进行延迟检查[server3]
hostname=172.25.254.30
no_master=1   #表示该服务器不会被选为主库

在这里插入图片描述

  • check_repl_delay=0默认情况下如果一个slave落后master 100Mrelay-log的话,MHA不会选择该slave作为一个master,因为对于这个slave恢复需要花费很长时间,通过设置check_repl_delay=0MHA触发切换在选择一个master的时候将会忽略复制延时,这个参数对于设置了candidate_master=1主机非常有用,因为这个候选主切换过程中一定是master
  • node1,node2,node3上任意一个主机上创建一个子接口
#这里我们在node3上创建一个子接口
[root@mysql-node3 ~]# ip address add 172.25.254.11/24 dev eth0
  • MHAssh私钥发送给node1,node2,node3
[root@mha ~]# rsync ~/.ssh/id_rsa root@172.25.254.10:/root/.ssh/[root@mha ~]# rsync ~/.ssh/id_rsa root@172.25.254.20:/root/.ssh/[root@mha ~]# rsync ~/.ssh/id_rsa root@172.25.254.30:/root/.ssh/

测试

#ssh检测
[root@mha ~]# masterha_check_ssh --conf=/etc/masterha/app1.conf

在这里插入图片描述

#repl检测
[root@mha ~]# masterha_check_repl --conf=/etc/masterha/app1.conf

在这里插入图片描述

模拟故障MySQL-master切换

  • 手动切换时,可以不删除锁文件,不设置--ignore_last_state参数,但是自动一定要删除锁文件

手动切换(在master存活状态下切换

#现在的master是node1
mysql> show master status\G;
*************************** 1. row ***************************File: master-bin.000002Position: 1279Binlog_Do_DB:Binlog_Ignore_DB:
Executed_Gtid_Set: 85cf422c-b472-11ef-be1a-000c2928b963:1-5
  • 手动切换(在MHA上做)
[root@mha ~]# masterha_master_switch \
> --conf=/etc/masterha/app1.conf \
> --master_state=alive \   #表示node1为存活状态
> --new_master_host=172.25.254.20 \
> --new_master_port=3306 \
> --orig_master_is_new_slave \  #原来的master变为slave
> --running_updates_limit=10000    #切换的超时时间为10秒
#一直yes回车
  • 查看node1状态
mysql> show slave status\G;

在这里插入图片描述

  • 查看node2状态

在这里插入图片描述

  • 查看node3状态

在这里插入图片描述

  • 手动master切换为node1
[root@mha ~]# masterha_master_switch \
> --conf=/etc/masterha/app1.conf \
> --master_state=alive \
> --new_master_host=172.25.254.10 \
> --new_master_port=3306 \
> --orig_master_is_new_slave \
> --running_updates_limit=10000
  • 查看node1状态

在这里插入图片描述

  • 查看node2状态

在这里插入图片描述

  • 查看node3状态

在这里插入图片描述

手动切换(在master死亡状态下切换

  • node1挂掉
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
  • 手动切换(在MHA上切换)
[root@mha ~]# masterha_master_switch \
> --master_state=dead \   #原master的状态
> --conf=/etc/masterha/app1.conf \
> --dead_master_host=172.25.254.10 \
> --dead_master_port=3306 \
> --new_master_host=172.25.254.20 \
> --new_master_port=3306 \
> --ignore_last_failove  #因为自动切换会生成锁文件
  • --ignore_last_failove表示忽略/etc/masterha/目录中在切换过程中生成的锁文件
  • 恢复故障
[root@mysql-node1 ~]# /etc/init.d/mysqld startmysql> change master to \-> master_host='172.25.254.20',-> master_user='huazi',-> master_password='123456',-> master_auto_position=1;mysql> start slave;
  • 查看node1状态

在这里插入图片描述

  • 查看node2状态

在这里插入图片描述

  • 查看node3状态

在这里插入图片描述

  • 手动切换node1
[root@mha ~]# masterha_master_switch \
> --conf=/etc/masterha/app1.conf \
> --master_state=alive \
> --new_master_host=172.25.254.10 \
> --new_master_port=3306 \
> --orig_master_is_new_slave \
> --running_updates_limit=10000

自动切换

[root@mha ~]# cd /etc/masterha/
[root@mha masterha]# ls
app1.conf  app1.failover.complete
  • app1.failover.complete是生成的锁文件,在做自动切换前,要删除这个锁文件
  • 自动切换时,一定要删除锁文件,否则下一次自动切换失败
[root@mha masterha]# rm -rf app1.failover.complete
[root@mha masterha]# ls
app1.conf
  • MySQL-master进行监控(在MHA上做)
[root@mha masterha]# masterha_manager --conf=/etc/masterha/app1.conf
Sun Dec  8 00:19:12 2024 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Sun Dec  8 00:19:12 2024 - [info] Reading application default configuration from /etc/masterha/app1.conf..
Sun Dec  8 00:19:12 2024 - [info] Reading server configuration from /etc/masterha/app1.conf..
#进程会一直运行着,等待着
  • 停掉node1,因为node1master
[root@mysql-node1 ~]# /etc/init.d/mysql.server stop
  • 发现master自动切换到了node2

在这里插入图片描述

  • 发现masterha_manager进程自动结束了

在这里插入图片描述

  • 一次故障监控masterha_manager进程结束了
  • 发现自动切换时生成了日志manager.log
[root@mha masterha]# ls
app1.conf  app1.failover.complete  manager.log
  • 恢复故障
[root@mysql-node1 ~]# /etc/init.d/mysqld start
  • 自动切换后,原来master不会自动成为slave,需要我们手动切换
[root@mysql-node1 ~]# mysql -uroot -p
Enter password:
mysql> show slave status\G;
Empty set (0.00 sec)#手动加入
mysql> change master to \-> master_host='172.25.254.20',-> master_user='huazi',-> master_password='123456',-> master_auto_position=1;mysql> start slave;mysql> show slave status\G;

在这里插入图片描述

MHA故障切换过程

  • 配置文件检查阶段,这个阶段检查整个集群配置文件中的配置内容
  • 宕机master处理这个阶段包括虚拟ip摘除操作,主机关机操作
  • 复制dead master最新slave相差的relay log,并保存MHA Manger具体的目录
  • 识别含有最新更新的slave
  • 应用从master保存的二进制日志事件binlog events
  • 提升一个slave新的master进行复制
  • 使其他的slave连接新的master进行复制

MHA添加vip功能

  • 防止真实MySQL主机切换后,ip变化,导致业务不通

上传两个脚本文件
在这里插入图片描述

  • master_ip_failover自动切换使用的脚本
  • master_ip_online_change手动切换使用的脚本
  • 添加到环境变量中,并赋予可执行权限
[root@mha ~]# cp master_ip_* /usr/local/bin/[root@mha ~]# chmod +x /usr/local/bin/master_ip_*
  • 修改master_ip_failover脚本内容
[root@mha ~]# 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 = '172.25.254.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev eth0";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev eth0";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";
}

在这里插入图片描述

  • 修改master_ip_online_change脚本内容
[root@mha ~]# vim /usr/local/bin/master_ip_online_change
#!/usr/bin/env perl
use strict;
use warnings FATAL =>'all';use Getopt::Long;my $vip = '172.25.254.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev eth0";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev eth0";
my $exit_code = 0;my ($command,              $orig_master_is_new_slave, $orig_master_host,$orig_master_ip,       $orig_master_port,         $orig_master_user,$orig_master_password, $orig_master_ssh_user,     $new_master_host,$new_master_ip,        $new_master_port,          $new_master_user,$new_master_password,  $new_master_ssh_user,
);
GetOptions('command=s'                => \$command,'orig_master_is_new_slave' => \$orig_master_is_new_slave,'orig_master_host=s'       => \$orig_master_host,'orig_master_ip=s'         => \$orig_master_ip,'orig_master_port=i'       => \$orig_master_port,'orig_master_user=s'       => \$orig_master_user,'orig_master_password=s'   => \$orig_master_password,'orig_master_ssh_user=s'   => \$orig_master_ssh_user,'new_master_host=s'        => \$new_master_host,'new_master_ip=s'          => \$new_master_ip,'new_master_port=i'        => \$new_master_port,'new_master_user=s'        => \$new_master_user,'new_master_password=s'    => \$new_master_password,'new_master_ssh_user=s'    => \$new_master_ssh_user,
);exit &main();sub main {#print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";if ( $command eq "stop" || $command eq "stopssh" ) {# $orig_master_host, $orig_master_ip, $orig_master_port are passed.# If you manage master ip address at global catalog database,# invalidate orig_master_ip here.my $exit_code = 1;eval {print "\n\n\n***************************************************************\n";print "Disabling the VIP - $vip on old master: $orig_master_host\n";print "***************************************************************\n\n\n\n";
&stop_vip();$exit_code = 0;};if ($@) {warn "Got Error: $@\n";exit $exit_code;}exit $exit_code;
}
elsif ( $command eq "start" ) {# all arguments are passed.# If you manage master ip address at global catalog database,# activate new_master_ip here.# You can also grant write access (create user, set read_only=0, etc) here.
my $exit_code = 10;eval {print "\n\n\n***************************************************************\n";print "Enabling the VIP - $vip on new master: $new_master_host \n";print "***************************************************************\n\n\n\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 $orig_master_ssh_user\@$orig_master_host \" $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 $new_master_ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}
# A simple system call that disable the VIP on the old_master
sub stop_vip() {
`ssh $orig_master_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";
}

在这里插入图片描述

  • 打开MHAvip功能
[root@mha ~]# vim /etc/masterha/app1.conf

在这里插入图片描述

  • vip需要手动添加(因为此时masternode2上,所以我们给node2添加一个vip
[root@mysql-node2 ~]# ip address add 172.25.254.100/24 dev eth0

测试1(自动故障切换

  • 监控master(在MHA上做)
#先删除锁文件
[root@mha ~]# cd /etc/masterha/
[root@mha masterha]# ls
app1.conf  app1.failover.complete  manager.log
[root@mha masterha]# rm -rf app1.failover.complete
[root@mha ~]# masterha_manager --conf=/etc/masterha/app1.conf
Sun Dec  8 01:32:22 2024 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Sun Dec  8 01:32:22 2024 - [info] Reading application default configuration from /etc/masterha/app1.conf..
Sun Dec  8 01:32:22 2024 - [info] Reading server configuration from /etc/masterha/app1.conf..
  • node2上模拟故障
#将node2上的MySQL停掉
[root@mysql-node2 ~]# /etc/init.d/mysql.server stop
  • 发现原来在node2上的vip移到了node1

在这里插入图片描述

  • node1成为了master

在这里插入图片描述

  • 恢复故障
[root@mysql-node2 ~]# /etc/init.d/mysql.server start
  • 手动加入
[root@mysql-node2 ~]# mysql -uroot -p
Enter password:
mysql> show slave status\G;
Empty set (0.00 sec)#手动加入
mysql> change master to \-> master_host='172.25.254.10',-> master_user='huazi',-> master_password='123456',-> master_auto_position=1;mysql> start slave;

在这里插入图片描述

测试2 (通过vip登录数据库)

[root@mysql-node3 ~]# mysql -h 172.25.254.100 -uroot -p123456mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|          10 |
+-------------+

相关文章:

MySQL高可用之MHA

华子目录 MHA概述为什么要用MHA什么是MHAMHA的组成MHA的特点故障切换备选主库的算法 MHA工作原理MHA环境搭建环境准备开始部署MHAMHA软件使用介绍配置MHA的管理环境创建MHA管理的模板文件 测试 模拟故障MySQL-master切换手动切换(在master存活状态下切换&#xff09…...

区块链——基本概念、技术原理

一、区块链基本概念 (一)区块链定义 区块链(Blockchain)是指通过去中心化和去信任的方式集体维护一个可靠数据库的技术方案。通俗一点说,区块链技术就指一种全民参与记账的方式,是一种防篡改、共享的、可…...

docker 部署共享文档ZFile

1、拉取ZFile镜像 docker pull crpi-k5k93ldwfc7o75ip.cn-hangzhou.personal.cr.aliyuncs.com/tirling-pdf/zfile:latest 2、创建文件夹和进入文件夹 mkdir zfile && cd zfile 3、创建docker-compose.yml配置文件。 vim docker-compose.yml version: 3.3 service…...

C# 自定义组件实现表格的多层表头功能

在 WinForms 中,想要实现多层表头功能时,DataGridView 本身并不支持该功能,而且又不希望使用第三方控件,因此选择通过自定义组件来实现这一需求。 首先,展示一下程序实现的效果: 接下来,创建一…...

给Squid代理添加HTTP basic认证

HTTP basic认证是一种简单的认证机制,要求用户在请求资源前提供有效的用户名和密码。 实例: 给Squid代理添加HTTP basic认证 要求: 只允许用户名为peter,密码为123的请求通过认证, 其他请求返回407(Proxy认证失败) 步骤 1 使用htpasswd工具,生成用户…...

使用伪装IP地址和MAC地址进行Nmap扫描

使用伪装IP地址和MAC地址进行Nmap扫描 在某些网络设置中,攻击者可以使用伪装的IP地址甚至伪装的MAC地址进行系统扫描。这种扫描方式只有在可以保证捕获响应的情况下才有意义。如果从某个随机的网络尝试使用伪装的IP地址进行扫描,很可能无法接收到任何响…...

Oceanbase离线集群部署

准备工作 两台服务器 服务器的配置参照官网要求来 服务器名配置服务器IPoceanbase116g8h192.168.10.239oceanbase216g8h192.168.10.239 这里选oceanbase1作为 obd机器 oceanbase安装包 选择社区版本的时候自己系统的安装包 ntp时间同步rpm包 联网机器下载所需的软件包 …...

剑指Offer-1 存在重复元素

记录学习过程 题目连接 题目连接 题目描述 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。 示例一、 输入:nums [1,2,3,1] 输出:true 解释&…...

react跳转传参的方法

传参 首先下载命令行 npm react-router-dom 然后引入此代码 前面跳转的是页面 后面传的是你需要传的参数接参 引入此方法 useLocation():这是 react-router-dom 提供的一个钩子,用于获取当前路由的位置对象location.state:这是从其他页面传…...

【Java若依框架】RuoYi-Vue的前端和后端配置步骤和启动步骤

🎙告诉你:Java是世界上最美好的语言 💎比较擅长的领域:前端开发 是的,我需要您的: 🧡点赞❤️关注💙收藏💛 是我持续下去的动力! 目录 一. 作者有话说 …...

CSS学习记录04

CSS边框 CSS border 属性指定元素边框的样式、宽度和颜色。border-style 属性指定要显示的边框类型。dotted - 定义点线边框dashed - 定义虚线边框solid - 定义实线边框double - 定义双边框groove - 定义3D坡口边框,效果取决于border-color值ridge - 定义3D脊线边框…...

Kafka怎么发送JAVA对象并在消费者端解析出JAVA对象--示例

1、在pom.xml中加入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-stream-kafka</artifactId><version>3.1.6</version></dependency> 2、配置application.yml 加入Kafk…...

vue3【实战】图表【组件封装】Chart ( 原生 ECharts ,支持自适配屏幕缩放,动态响应图表配置修改)

效果预览 技术方案 vue3 ( vite | TS | AutoImport ) Element Plus UnoCSS ECharts 技术要点 ECharts 实例的类型 let myChart: echarts.ECharts | null null默认生成随机 id id: {type: String,default: () > Math.random().toString(36).substring(2, 8)},深度监听图…...

Oracle系统性能监控工具oswatcher演示

1、关于 OSW OSWatcher 的使用符合 Oracle 的标准许可条款&#xff0c;并且不需要额外的许可即可使用&#xff01;&#xff01;&#xff01;&#xff01; OSWatcher (oswbb) 是一种 UNIX shell 脚本的集合&#xff0c;主要用于收集和归档操作系统和网络的度量&#xff0c;以便…...

Unix、GNU、BSD 风格中 ps 参数的区别

注&#xff1a;本文为“不同风格中 ps 命令参数的区别”相关文章合辑。 未去重。 BSD 风格和 UNIX 风格中 ps 参数的区别 作者&#xff1a;Daniel Stori 译者&#xff1a;LCTT Name1e5s | 2017-06-17 10:53 One Last Question ps aux 以及 ps -elf 都是查看进程的方式&…...

Jenkins环境一站式教程:从安装到配置,打造高效CI/CD流水线环境-Ubuntu 22.04.5 环境离线安装配置 Jenkins 2.479.1

文章目录 Jenkins环境一站式教程&#xff1a;从安装到配置&#xff0c;打造高效CI/CD流水线环境-Ubuntu 22.04.5 环境离线安装配置 Jenkins 2.479.1一、环境准备1.1 机器规划1.2 环境配置1.2.1 设置主机名1.2.2 停止和禁用防火墙1.2.3 更新系统 二、安装配置Jenkins2.1 安装JDK…...

百度文心一言全解析

一、技术基础 模型架构 多层神经网络构建&#xff1a;深度神经网络结构&#xff0c;包含多个隐藏层&#xff0c;有效处理复杂语言信息。注意力机制运用&#xff1a;精准聚焦文本关键部分&#xff0c;理解语义关联与重要性分布。多头注意力并行&#xff1a;多维度分析文本&#…...

在python中使用布尔逻辑

布尔是python中常见类型。它的值只能是两项内容之一&#xff1a;true或false. 编写"if"语句 若要在python中表达条件逻辑&#xff0c;可以使用if语句。——编写If语句离不开逻辑运算符&#xff1a;等于、不等于、小于、大于或等于、大于和大于或等于。 在python中…...

【Web】AlpacaHack Round 7 (Web) 题解

Treasure Hunt flag在md5值拼接flagtxt的文件里&#xff0c;如 d/4/1/d/8/c/d/9/8/f/0/0/b/2/0/4/e/9/8/0/0/9/9/8/e/c/f/8/4/2/7/e/f/l/a/g/t/x/t 访问已经存在的目录状态码是301 访问不存在的目录状态码是404 基于此差异可以写爆破脚本 这段waf可以用url编码绕过 做个lab …...

汽车48V电气系统

汽车48V电气系统 汽车48V电气系统汽车48V电气系统设计汽车48V电气系统测试汽车48V系统是48V供电和12V供电共存的么?48V供电系统是如何与12V供电系统共存的?48V电气系统测试的难点有哪些?在汽车48V电气系统通信测试中,如何向12V的控制器和48V的控制器供电?汽车48V电气系统通…...

完美解决Qt Qml窗口全屏软键盘遮挡不显示

1、前提 说明&#xff1a;我使用的是第三方软键盘 QVirtualKeyboard QVirtualKeyboard: Qt5虚拟键盘支持中英文,仿qt官方的virtualkeyboard模块,但使用QWidget实现。 - Gitee.com 由于参考了几篇文章尝试但没有效果&#xff0c;链接如下&#xff1a; 文章一&#xff1a;可能…...

docker逃逸总结

一、 检查是否在docker容器中 通过以下两个地方来判断 # 是否存在此文件 ls -al /.dockerenv# 在其中是否包含docker字符串 cat /proc/1/cgroup除了上面两种外还有其他方式判断&#xff0c;如检测mount、fdisk -l查看硬盘 、判断PID 1的进程名等也可用来辅助判断。 容器逃逸…...

DSA 和 ECDSA 签名算法

DSA 和 ECDSA 签名算法 基本介绍Java实现DSA创建密钥对签名验签 ECDSA创建密钥对签名验签 Go实现ECDSA创建密钥对签名验签 DSA创建密钥对签名验签 基本介绍 DSA 是一种基于离散对数问题的数字签名算法。它使用私钥和公钥对来进行签名和验证操作。 ECDSA 是基于椭圆曲线密码体制…...

Scrapy的简单实现

Scrapy的简单实现 1. Scrapy是什么 Scrapy是一个用于抓取网站&#xff08;即网页爬取&#xff09;和从网页中提取结构化数据的开源框架。它为编写网络爬虫来抓取网站内容提供了高效、灵活的方式&#xff0c;并将这些信息以常见的格式保存&#xff0c;如JSON、CSV或XML。Scrap…...

Python之爬虫入门--示例(2)

一、Requests库安装 可以使用命令提示符指令直接安装requests库使用 pip install requests 二、爬取JSON数据 &#xff08;1&#xff09;、点击网络 &#xff08;2&#xff09;、刷新网页 &#xff08;3&#xff09;、这里有一些数据类型&#xff0c;选择全部 &#xff08…...

JS的for in和for of

for...in 语句 工作原理 遍历属性&#xff1a;for...in 遍历对象的所有可枚举属性&#xff0c;这些属性不仅限于对象本身的属性&#xff0c;还包括原型链上的可枚举属性。返回键名&#xff1a;每次迭代时&#xff0c;循环变量会得到当前属性的键&#xff08;即字符串形式的属…...

Spring IoC的基本概念

引言 在 Java 中&#xff0c;出现了大量轻量级容器&#xff0c;这些容器有助于将来自不同项目的组件组装成一个有凝聚力的应用程序。这些容器的底层是它们如何执行布线的常见模式&#xff0c;它们将这一概念称为“控制反转”。 &#x1f3e2; 本章内容 &#x1f3ed; IoC服务…...

解决GitHub项目泄露API密钥问题

文章目录 所有的步骤参考gpt步骤一 使用环境变量步骤二 撤销并移除历史中的API密钥(1) 安装: pip install git-filter-repo(2) 清除特定文件 git filter-repo --path PATH_TO_YOUR_FILE --invert-paths出错解决 步骤三 处理移除的 origin 远程步骤四 强制推送到GitHub步骤五 重…...

【BUG】VMware|vmrest正在运行此虚拟机,无法配置或删除快照

VMware版本&#xff1a;VMware 16 文章目录 省流版问题解决方案 详细解释版问题解决方案总结 省流版 问题 只读&#xff0c;因为vmrest正在运行虚拟机。 解决方案 参考&#xff1a;虚拟机设置&#xff0c;只读&#xff0c;因为vmrest正在运行此虚拟机。有谁遇到过这种问题吗&…...

Ruby On Rails 笔记2——表的基本知识

Active Record Basics — Ruby on Rails Guides Active Record Migrations — Ruby on Rails Guides 原文链接自取 1.Active Record是什么&#xff1f; Active Record是MVC模式中M的一部分&#xff0c;是负责展示数据和业务逻辑的一层&#xff0c;可以帮助你创建和使用Ruby…...

VideoConvertor.java ffmpeg.exe

VideoConvertor.java ffmpeg.exe 视频剪切原理 入点 和 出点 选中时间点&#xff0c;导出...

java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigur

在运行代码的过程中&#xff0c;报出以下错误&#xff1a; java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.redisTemplate 或者是&#xff1a; Caused by: java.lang.IllegalArgu…...

C#设计模式--策略模式(Strategy Pattern)

策略模式是一种行为设计模式&#xff0c;它使你能在运行时改变对象的行为。在策略模式定义了一系列算法或策略&#xff0c;并将每个算法封装在独立的类中&#xff0c;使得它们可以互相替换。通过使用策略模式&#xff0c;可以在运行时根据需要选择不同的算法&#xff0c;而不需…...

Webpack Tree Shaking 技术原理及应用实战,优化代码,精简产物

前言 在前端开发中&#xff0c;优化代码体积和提升应用性能是至关重要的课题。Webpack 提供了多种优化手段来帮助开发者实现这一目标&#xff0c;Tree Shaking 就是其中一种非常重要的优化技术&#xff0c;它通过在编译阶段移除未被使用的代码模块&#xff0c;从而显著减小最终…...

C++(十二)

前言&#xff1a; 本文将进一步讲解C中&#xff0c;条件判断语句以及它是如何运行的以及内部逻辑。 一&#xff0c;if-else,if-else语句。 在if语句中&#xff0c;只能判断两个条件的变量&#xff0c;若想实现判断两个以上条件的变体&#xff0c;就需要使用if-else,if-else语…...

ModelScope-Agent(1): 基于开源大语言模型的可定制Agent系统

目录 简介快速入门 简介 github地址 快速入门 看前两篇&#xff0c;调用千问API和天气API # 选用RolePlay 配置agent from modelscope_agent.agents.role_play import RolePlay # NOQArole_template 你扮演一个天气预报助手&#xff0c;你需要查询相应地区的天气&#x…...

Jmeter进阶篇(30)深入探索 JMeter 监听器

前言 在性能测试领域里,Apache JMeter 是一款经典而强大的工具,而其中的监听器(Listeners)组件更是发挥着不可或缺的关键作用。 监听器就像敏锐的观察者,默默记录测试执行过程中的各种数据,作为系统性能分析的数据依据。 本文将带你全方位走进 JMeter 监听器的奇妙世界,…...

HTTP multipart/form-data 请求

序言 最近在写项目的过程中有一个需求是利用 HTTP 协议传输图片和视频&#xff0c;经过查询方法相应的方法发现使用 multipart/form-data 的方式&#xff0c;这是最常见处理二进制文件的表单编码类型。  学习了一下午&#xff0c;现在总结一下使用的方法和相关的知识点&#x…...

记录关于阿里云智能媒体预览pdf文件的问题

pdf仅支持预览&#xff0c;不支持编辑&#xff0c;需要将权限设置成只读。 readonly参数一定要传&#xff0c;不能不传&#xff01;&#xff01;&#xff01;&#xff01; readonly的设置一定要用示例提供的方法&#xff01;&#xff01;&#xff01;&#xff01; 用WebofficeP…...

Milvus向量数据库01-基础概念

Milvus向量数据库01-基础概念 Zilliz Cloud 集群由全托管 Milvus 实例及相关计算资源构成。您可以在 Zilliz Cloud 集群中创建 Collection&#xff0c;然后在 Collection 中插入 Entity。Zilliz Cloud 集群中的 Collection 类似于关系型数据库中的表。Collection 中的 Entity …...

字节高频算法面试题:小于 n 的最大数

问题描述&#xff08;感觉n的位数需要大于等于2&#xff0c;因为n的位数1的话会有点问题&#xff0c;“且无重复”是指nums中存在重复&#xff0c;但是最后返回的小于n最大数是可以重复使用nums中的元素的&#xff09;&#xff1a; 思路&#xff1a; 先对nums倒序排序 暴力回…...

PowerShell 脚本实战:解决 GitLab 仓库文件批量重命名难题

使用PowerShell脚本解决文件重命名问题&#xff1a;一次实践经验分享 在软件开发过程中&#xff0c;我们经常会遇到需要批量处理文件的情况。最近&#xff0c;我在一个项目中就遇到了这样一个需求&#xff1a;将GitLab仓库中所有的.ts和.py文件的扩展名修改为原扩展名加上&quo…...

爬取的数据能实时更新吗?

在当今数字化时代&#xff0c;实时数据更新对于企业和个人都至关重要。无论是市场分析、商品类目监控还是其他需要实时数据的应用场景&#xff0c;爬虫技术都能提供有效的解决方案。本文将探讨如何利用PHP爬虫实现数据的实时更新&#xff0c;并提供相应的代码示例。 1. 实时数…...

【SKFramework框架核心模块】3-6、FSM有限状态机模块

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【Unity3D框架】SKFramework框架完全教程《全…...

Python之爬虫入门(1)

目录 一、简介 二、爬虫的功能 1、爬虫的用处 2、爬虫的应用场景 三、爬虫的实现步骤 四、GET和POST方法 1、GET方法 &#xff08;1&#xff09;、简介 &#xff08;2&#xff09;、适用场景 2、POST方法 &#xff08;1&#xff09;、简介 &#xff08;2&#xff09;…...

《MySQL 表结构设计基础》

一、引言 MySQL 表结构设计是数据库开发中的重要环节&#xff0c;合理的设计不仅能提高数据库性能&#xff0c;还能使数据更易于维护和管理。本文将详细介绍 MySQL 表结构设计的基础要点。 在数据库开发中&#xff0c;MySQL 表结构设计的重要性不言而喻。一个良好的表结构设计…...

微信小程序 - 解决报错{“errno“:600001,“errMsg“:“request:fail errcode:-202cronet_error_code:-202error_msg:net::

前言 关于此问题网上的教程都无法解决,如果您的报错信息与我相似,即可解决。 在微信小程序开发中,详细解决小程序请求接口报错:{“errno”:600001,“errMsg”:“request:fail errcode:-202cronet_error_code:-202error_msg:net::ERR_CERT_AUTH ORITY_INVALID”},微…...

k8s 为什么需要Pod?

Pod&#xff0c;是 Kubernetes 项目中最小的 API 对象&#xff0c;更加专业的说&#xff0c;Pod&#xff0c;是 Kubernetes 项目的原子调度单位。 Pod 是 Kubernetes 里的原子调度单位。这就意味着&#xff0c;Kubernetes 项目的调度器&#xff0c;是统一按照 Pod 而非容器的资…...

react 使用状态管理调用列表接口渲染列表(包含条件查询,统一使用查询按钮,重置功能),避免重复多次调用接口的方法

react开发调用api接口一般使用useEffect来监听值的变化&#xff0c;通过值的变化与否来进行接口调用。 比如我们要进行一个查询接口 const [pageParams, setPage] useState({name: ,id: ,});const [dataList, setDataList] useState([]);const getList async () > {const…...

常见限流算法详细解析

常见限流算法详细解析 分布式系统中&#xff0c;由于接口API无法控制上游调用方的行为&#xff0c;因此当瞬时请求量突增时&#xff0c;会导致服务器占用过多资源&#xff0c;发生响应速度降低、超时、乃至宕机&#xff0c;甚至引发雪崩造成整个系统不可用。 限流&#xff0c;…...