• Post author:
  • Post category:mysql
  • Post comments:0评论

一、简介

  MHA能够在较短的时间内实现自动故障检测和故障转移,通常在10-30秒以内。在主从框架中,MHA能够很好地解决主从复制过程中的数据一致性问题,由于不需要在现有的主从框架中添加额外的服务器,仅需要一个manager节点,而一个Manager能管理多套复制,所以能大大地节约服务器的数量。另外,安装简单,无性能损耗,以及不需要修改现有的复制部署也是它的优势之处。
  MHA可以监控主从复制环境中的主库,并在检测到主库故障时执行自动主库故障转移,当主库出现故障时,它可以自动将最新数据的从库提升为新的主库,然后将所有其它的从库重新指向新的主库。
  MHA还提供在线主库切换功能,能够将当前运行的主库安全的切换到一个新的主库(通过将从库提升为主库),能在0.5-2秒内完成,在切换过程中仅阻止写入。
  官方文档:https://github.com/yoshinorim/mha4mysql-manager/wiki/Overview
  下载地址:https://github.com/yoshinorim/mha4mysql-manager/wiki/Downloads

二、体系结构

  MHA由两部分组成:MHA Manager(管理节点)和MHA Node(数据节点)。MHA Manager可以独立部署在一台独立的机器上管理多个Master-Slave集群,也可以部署在一台Slave上。
  Manager组件结构:

 •  masterha_manger                启动MHA 
 •  masterha_check_ssh             检查MHA的SSH配置状况 
 •  masterha_check_repl            检查MySQL复制状况 
 •  masterha_master_monitor        检测master是否宕机 
 •  masterha_check_status          检测当前MHA运行状态 
 •  masterha_master_switch         控制故障转移(自动或者手动)
 •  masterha_conf_host             添加或删除配置的server信息

  node 组件结构:

 •  save_binary_logs             保存和复制master的二进制日志 
 •  apply_diff_relay_logs        识别差异的中继日志事件并将其差异的事件应用于其它的从库
 •  purge_relay_logs             清除中继日志(不会阻塞SQL线程)

三、故障转移原理

  以一主多从为例,如果主库崩溃,MHA则会选择一个数据最新的从库,将其提升为新的主库,然后让其它从库从新的主库开始复制。实际上,这并本不是一件小事。即使可以识别出最新的从库,其他从库也有可能尚未收到所有二进制日志事件。要知道MySQL主从复制是异步的,某些(或没有一个)从库可以从崩溃的主库接收到所有二进制日志事件,也有可能只有一些从库收到了最新事件。
  如果就此重新依据新主库构建主从复制,则这些从库将会丢失事务,这将导致数据一致性问题。为了避免这些一致性问题,丢失的binlog事件(尚未到达所有从库)需要被识别,然后在依据新主库上启动复制之前,依次将其应用于每个从库,即从库互相识别差异互补。MHA会通过识别来自最新从库的差异中继日志事件,并将其应用于所有其它从库,包括那些尚未收到最新中继日志事件的从库,来保证所有从库的一致性。
  MHA的目标是在没有任何备用服务器的情况下,尽快使主库故障转移和恢复过程完全自动化。恢复包括确定新的主库、识别从库之间的差异中继日志事件、将差异的事件应用于新的主库、同步其它从库并使它们从新的主库开始复制。根据复制延迟,MHA通常可以在10到30秒的停机时间内完成故障转移。

具体流程如下:

1、监控
  通过masterha_master_monitor ,每隔 ping_interval 秒探测一次主库心跳。
  如果探测不到心跳,一共给4次机会,如果还探测不到就会认为主库宕机。

2、选主
(1)从判断各个从库的日志(position或者GTID)选,最接近主库的从库,成为备选主。
(2)在配置文件中,可以将特定从库指定为候选主库(通过设定权重 candidate_master=1 )如果有则优先按照权重指定为候选主库。注意仅仅只是候选主库而已。
    •  默认情况下如果一个从库落后主库 100M的relay logs的话,即使有权重,也没用。
    •  如果设定了"check_repl_delay=0"的话,即使落后很多日志,也会被选为候选主库。
(3)如果从库日志数据一致,则按照配置文件顺序选主。
(4)整体来说,选主策略优先级:最新日志+候选主库 > 最新日志 > 候选主库 > 配置文件顺序。

3、日志补偿
(1)如果主库SSH能连接,则从库会对比主库position或者GTID 号,save_binary_logs会立即将二进制日志保存至各个从节点并且应用。
(2)如果主库SSH不能连接,则通过apply_diff_relay_logs对比从库之间的relay log日志的差异。

4、故障转移
  取消所有节点的从库状态,构建新的主从关系。自动将故障节点,从配置文件剔除。

5、自动退出
  完成故障转移后,manager会自动退出,所以它是一次性的,只能完成一次切换。
  完成转移后,我们需要重新启动MHA和及时修复故障节点,因此,我们需要配置邮件通知。

四、MHA搭建

1、节点规划

节点名称 ip地址 角色
db01 10.0.0.51 主库
db02 10.0.0.52 从库
db03 10.0.0.53 从库

2、主从构建
主库db01操作:

(1)开启binlog日志
[root@db01 ~]# vim/etc/my.cnf       # 在mysqld下添加以下配置
server_id=1
log_bin=/service/data/binlog/mysql-bin

(2)主库创建专门用于复制的用户
mysql> grant replication slave on *.* to repl@'10.0.0.%' identified by '000000';

从库db02、db03操作:主从时间要同步

1、修改配置文件
[root@db02 ~]# vim/etc/my.cnf       # 在mysqld下添加以下配置
server_id=2 
log_bin=/service/data/binlog/mysql-bin

2、配置从库(因为没啥数据,也不关注太多,直接从头开始复制)
mysql> change master to
       master_host='10.0.0.51',
       master_user='repl',
       master_password='000000',
       master_port=3306,
       master_log_file='mysql-bin.000001',
       master_log_pos=1;

4、启动从库的复制功能
mysql> start slave;

5、检查从库复制功能状态
mysql> show slave status \G
......
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
......


3、安装软件
所有节点安装node

[root@db01 ~]# yum install perl-DBD-MySQL -y
[root@db01 ~]# rpm -vih mha4mysql-node-0.56-0.el6.noarch.rpm 

db03节点安装manger

[root@db03 ~]# yum install -y epel-release perl-Config-Tiny  perl-Time-HiRes
[root@db03 ~]# yum install -y perl-Log-Dispatch perl-Parallel-ForkManager
[root@db03 ~]# rpm -ivh mha4mysql-manager*.rpm


4、各节点准备工作

(1)各节点配置关键程序软链接(MHA会去使用以下链接的全路径去调用,代码写死的所以需要做软链接)
[root@db01 ~]# ln -s /service/app/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
[root@db01 ~]# ln -s /service/app/mysql/bin/mysql /usr/bin/mysql

(2)配置互信(免密ssh)
各节点:
[root@db01 ~]# sed -i '/StrictHostKeyChecking/c StrictHostKeyChecking no' /etc/ssh/ssh_config
db01节点:
[root@db01 ~]# rm -rf /root/.ssh 
[root@db01 ~]# ssh-keygen
[root@db01 ~]# cd /root/.ssh 
[root@db01 ~]# mv id_rsa.pub authorized_keys
[root@db01 ~]# scp -r /root/.ssh 10.0.0.52:/root 
[root@db01 ~]# scp -r /root/.ssh 10.0.0.53:/root 

(3)各节点验证
[root@db01 ~]# ssh 10.0.0.51 hostname
db01
[root@db01 ~]# ssh 10.0.0.52 hostname
db02
[root@db01 ~]# ssh 10.0.0.53 hostname
db03


5、在db01主库中创建mha管理用户

mysql> grant all privileges on *.* to mha@'10.0.0.%' identified by 'mha';

6、配置文件准备(db03)

(1)创建配置文件目录和日志目录
[root@db03 ~]# mkdir -p /etc/mha
[root@db03 ~]# mkdir -p /var/log/mha/app1

(2)编辑mha配置文件
[root@db03 ~]# vim /etc/mha/app1.cnf
[server default]
user=mha                                # MHA管理用户
password=mha                            # MHA管理用户密码
manager_workdir=/var/log/mha/app1       # 工作目录
manager_log=/var/log/mha/app1/app1.log  # 日志位置
master_binlog_dir=/service/data/binlog/ # 主库binlog目录
ping_interval=1                         # 探测主库存货的间隔时间
repl_user=repl                          # 主从复制管理用户
repl_password=000000                    # 主从复制管理用户密码
ssh_user=root                           # ssh连接用户

[server1]                                   
hostname=10.0.0.51
port=3306                                  

[server2]            
hostname=10.0.0.52
port=3306

[server3]
hostname=10.0.0.53
port=3306


7、状态检查

(1)互信检查
[root@db03 ~]# masterha_check_ssh --conf=/etc/mha/app1.cnf  

(2)主从状态检查
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf 


8、开启MHA

[root@db03 ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

命令参数说明:
nohup                           后台启动
masterha_manager                MHA启动程序
--conf=/service/mha/app1.cnf    指定配置文件
--remove_dead_master_conf       移除崩溃的主库节点配置
--ignore_last_failover          忽略最后一次切换

安全机制说明:
    1.完成一次切换后,会生成一个锁文件。
    2.再次进行切换时,会检查锁文件。
    3.如果锁文件存在,则不能进行切换,8小时后才能进行再次切换。
    4.所以配置--ignore_last_failover进行跳过。


9、查看MHA状态

[root@db03 ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:11077) is running(0:PING_OK), master:10.0.0.51


10、建议添加配置
以上MHA环境已经构建完成,以下是建议配置的mysql配置:

(1)关闭自动删除relay log的功能
    relay_log_purge=0

(2)从库配置只读
    read_only=1

(3)从库开启保存binlog
    log_slave_updates

五、故障转移演示

1、关闭db01数据库模拟故障
[root@db01 ~]# systemctl stop mysqld

2、db03查看manager日志
[root@db03 ~]# vim /var/log/mha/app1/app1.log
......
Started automated(non-interactive) failover.
The latest slave 10.0.0.52(10.0.0.52:3306) has all relay logs for recovery.
Selected 10.0.0.52(10.0.0.52:3306) as a new master.
10.0.0.52(10.0.0.52:3306): OK: Applying all logs succeeded.
10.0.0.53(10.0.0.53:3306): This host has the latest relay log events.
Generating relay diff files from the latest slave succeeded.
10.0.0.53(10.0.0.53:3306): OK: Applying all logs succeeded. Slave started, replicating from 10.0.0.52(10.0.0.52:3306)
10.0.0.52(10.0.0.52:3306): Resetting slave info succeeded.
Master failover to 10.0.0.52(10.0.0.52:3306) completed successfully.

通过日志发现主库已经切换到了db02

3、db03查看从库状态
mysql> show slave status \G
......
                  Master_Host: 10.0.0.52
                  Master_User: repl
                  Master_Port: 3306
......

节点修复重新构建主从

[root@db01 ~]# systemctl start mysqld

mysql> change master to
       master_host='10.0.0.52',
       master_user='repl',
       master_password='000000',
       master_port=3306,
       master_log_file='mysql-bin.000001',
       master_log_pos=1;

mysql> start slave;
mysql> show slave status \G
......
                  Master_Host: 10.0.0.52
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
......

重新部署MHA

1、将db01节点重新加入MHA环境
[root@db01 ~]# vim /etc/mha/app1.cnf    # 添加
[server1]
hostname=10.0.0.51
port=3306

2、重新检查状态
[root@db03 ~]# masterha_check_ssh --conf=/etc/mha/app1.cnf  
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf 

3、重新启动MHA
[root@db03 ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

4、检查
[root@db03 ~]# masterha_check_status --conf=/etc/mha/app1.cnf 
app1 (pid:11089) is running(0:PING_OK), master:10.0.0.52

六、VIP

  前面我们进行主库故障转移演示,主库成功由10.0.0.51切换到了10.0.0.52。那么大家想到没,对于连接数据库的应用来而言该怎么办呢?因为主库ip地址的变化,为了能让应用正常服务,需要修改代码重新上线。那么这显然不是我们所期望,因此MHA也给我们提供了VIP地址漂移的功能。应用绑定VIP,VIP处于主库,当主库宕机了,主库切换到新库,VIP跟着漂移到新库,对于应用而言还是连接着主库。
  对于VIP,MHA是通过调用脚本实现的,官方给我们提供了脚本。下载地址:https://github.com/yoshinorim/mha4mysql-manager/archive/master.zip,脚本位于下载文件中的samples/scripts中,注意官方提供的脚本只是个模板,是不能直接用的,需要进行修改。
  以下提供修改后的几个脚本下载地址:https://www.cpweb.top/wp-content/uploads/2020/11/scripts.zip

1、下载脚本
[root@db03 ~]# https://www.cpweb.top/wp-content/uploads/2020/11/scripts.zip
[root@db03 ~]# unzip scripts.zip -d /usr/local/bin/
[root@db03 ~]# chmod +x /usr/local/bin/*

2、根据服务器自身情况修改脚本
[root@db03 bin]# cd /usr/local/bin/
[root@db03 bin]# vim master_ip_failover     # 修改以下配置

my $vip = '10.0.0.50/24';       # VIP地址
my $key = '1';                  # 网卡后面数字
my $if  = 'ens33';              # 指定VIP绑定网卡
my $ssh_start_vip = "/sbin/ifconfig $if:$key $vip";     # 生成VIP
my $ssh_stop_vip = "/sbin/ifconfig  $if:$key down";     # 关闭VIP
my $ssh_Bcast_arp= "/sbin/arping -I $if -c 3 -A 10.0.0.50";     # arp广播

3、修改manager配置文件
[root@db03 ~]# vim /etc/mha/app1.cnf    # 在[server default]下添加以下配置
master_ip_failover_script=/usr/local/bin/master_ip_failover

4、重启MHA
[root@db03 ~]# masterha_stop  --conf=/etc/mha/app1.cnf 
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf 
[root@db03 ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

5、主库手工添加VIP 
[root@db02 ~]# ifconfig ens33:1 10.0.0.50/24

模拟故障,测试VIP地址漂移

1、主库模拟故障
[root@db02 ~]# systemctl stop mysqld

2、db03查看manager日志
Started automated(non-interactive) failover.
Invalidated master IP address on 10.0.0.52(10.0.0.52:3306)
The latest slave 10.0.0.51(10.0.0.51:3306) has all relay logs for recovery.
Selected 10.0.0.51(10.0.0.51:3306) as a new master.
10.0.0.51(10.0.0.51:3306): OK: Applying all logs succeeded.
10.0.0.51(10.0.0.51:3306): OK: Activated master IP address.
10.0.0.53(10.0.0.53:3306): This host has the latest relay log events.
Generating relay diff files from the latest slave succeeded.
10.0.0.53(10.0.0.53:3306): OK: Applying all logs succeeded. Slave started, replicating from 10.0.0.51(10.0.0.51:3306)
10.0.0.51(10.0.0.51:3306): Resetting slave info succeeded.
Master failover to 10.0.0.51(10.0.0.51:3306) completed successfully.

3、db01查看VIP
[root@db01 bin]# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:67:84:79 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.51/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.50/24 brd 10.0.0.255 scope global secondary ens33:1
       valid_lft forever preferred_lft forever
    inet6 fe80::3b3e:c579:6d22:26ef/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

4、db03查看从库状态
mysql> show slave status \G
......
                  Master_Host: 10.0.0.51
......

七、邮件通知故障转移

  因为MHA在完成故障转移后,manager会自动退出,为了重新去启动MHA和及时修复故障节点,我们需要去配置邮件通知。同样MHA通过调用脚本实现,脚本在上面下载的scripts包中。

1、修改脚本
[root@db03 bin]# vim send_report        # 根据情况修改以下配置

my $smtp='smtp.qq.com';       # smtp服务器
my $mail_from='xx@qq.com';    # 发件箱
my $mail_user='xx';           # 用户名
my $mail_pass='xx';           # 授权码
my $mail_to=['xx@qq.com'];    # 收件箱

2、修改manager配置文件
[root@db03 ~]# vim /etc/mha/app1.cnf   # 在[server default]下添加以下配置
report_script=/usr/local/bin/send_report

3、重启MHA
[root@db03 ~]# masterha_stop  --conf=/etc/mha/app1.cnf 
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf 
[root@db03 ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

模拟故障,收到邮件提醒:


八、binlog_server

  前面我们说到MySQL主从复制是异步的,当主库崩溃后,某些(或没有一个)从库可以从崩溃的主库接收到所有二进制日志事件,也有可能只有一些从库收到了最新事件。如果再这这种情况下,SSH不能连接到主库,那么从库只会通过apply_diff_relay_logs对比从库之间的relay log日志的差异进行互补。那么肯定会缺少部分数据,binlog_server 就是为了防止这样情况发生的,
  顾名思义binlog_server,即一台专门储存主库binlog日志文件的节点。当主库故障,从库SSH不能连接到主库时,从库会去这个节点去请求最新数据。为了方便下面我们将它部署在db03。

1、创建目录
[root@db03 ~]# mkdir -p /binlog_server
[root@db03 ~]# chown -R mysql.mysql /binlog_server
[root@db03 ~]# cd /binlog_server/

2、使用mysqlbinlog远程实时备份主库binlog
[root@db03 binlog_server]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:9097) is running(0:PING_OK), master:10.0.0.51

[root@db03 binlog_server]# mysqlbinlog -R --host=10.0.0.51 --user=mha --password=mha --raw --stop-never mysql-bin.000001 &

3、修改manager配置文件
[root@db03 ~]# vim /etc/mha/app1.cnf    # 添加

[binlog1]
no_master=1
hostname=10.0.0.53
master_binlog_dir=/binlog_server/

4、重启MHA 
[root@db03 ~]# masterha_stop  --conf=/etc/mha/app1.cnf
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf
[root@db03 ~]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

九、主库在线切换

  MHA给我们提供了在线切换主库的方法,通过masterha_master_switch 手动切换实现。主要有以下两种方式:

1、不调用脚本进行在线切换(不推荐)

[root@db03 ~]# masterha_stop --conf=/etc/mha/app1.cnf
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf 
[root@db03 ~]# masterha_master_switch  --conf=/etc/mha/app1.cnf --master_state=alive --new_master_host=10.0.0.52 --orig_master_is_new_slave --running_updates_limit=10000

 参数说明:
  --master_state=alive:  在主库存活情况下切换
  --new_master_host=xx:  指定新主库
  --orig_master_is_new_slave:  原来主库作为新主库
  --running_updates_limit=xx:  如果延迟超过xx毫秒,切换失败

注意:执行会收到以下问询和提示,意思是没有定义脚本,如果不手动在当前主库禁止写入,应用程序会继续写入数据。当然还有其它问询,自行填写。
master_ip_online_change_script is not defined. If you do not disable writes on the current master manually, applications keep writing on the current master. Is it ok to proceed? (yes/NO): yes

此种方法切换注意事项:
(1)原主库加FTWRL,否则会造成主从不一致。
(2)需要手工切换vip,脚本可以随着主库切换自动切换。
(3)发邮件功能无效


2、调用脚本进行在线切换(推荐)

(1)根据情况对脚本进行修改
[root@db03 ~]# vim /usr/local/bin/master_ip_online_change   

my $vip = "10.0.0.50/24";
my $key = "1";
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key $vip down";
my $ssh_Bcast_arp= "/sbin/arping -I ens33 -c 3 -A 10.0.0.50";

2、修改配置文件 
[root@db03 ~]# vim /etc/mha/app1.cnf    # 在[server default]下添加以下配置
master_ip_online_change_script=/usr/local/bin/master_ip_online_change

3、停止MHA
[root@db03 ~]# masterha_stop --conf=/etc/mha/app1.cnf 
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf 

4、在线切换
[root@db03 ~]# masterha_master_switch  --conf=/etc/mha/app1.cnf --master_state=alive --new_master_host=10.0.0.51 --orig_master_is_new_slave --running_updates_limit=10000

参考文章:
  https://www.jianshu.com/p/0f7b5a962ba7
  https://github.com/yoshinorim/mha4mysql-manager/wiki/Overview

发表评论

验证码: 8 + = 17