MHA高可用架构解决方案

MHA高可用架构解决方案

欢迎来到 来到大浪涛天的博客

一、MHA高可用架构解决方案

1. MHA的介绍

  • MHA(Master High Availability)目前在 MySQL 高可用方面是一个相对成熟的解决方案,它由日本 DeNA 公司的 youshimaton(现就职于 Facebook 公司)开发,是一套优秀的作为 MySQL 高可用性环境下故障切换和主从提升的高可用软件。
  • 在 MySQL 故障切换过程中,MHA 能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA 能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
  • 该软件由两部分组成:MHA Manager(管理节点)和 MHA Node(数据节点)。MHA Manager 可以单独部署在一台独立的机器上管理多个 master-slave 集群,也可以部署在一台 slave 节点上。MHA Node 运行在每台 MySQL 服务器上,MHA Manager 会定时探测集群中的 master 节点,当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master,然后将所有其他的 slave 重新指向新的 master。整个故障转移过程对应用程序完全透明。
  • 在 MHA 自动故障切换过程中,MHA 试图从宕机的主服务器上保存二进制日志,最大程度的保证数据的不丢失,但这并不总是可行的。例如,如果主服务器硬件故障或无法通过ssh访问,MHA 没法保存二进制日志,只进行故障转移而丢失了最新的数据,可以使用数据补偿模式,增加一个slave不用于切换只是用于拉取二进制日志。如果只有一个 slave 已经收到了最新的二进制日志,MHA 可以将最新的二进制日志应用于其他所有的 slave 服务器上,因此可以保证所有节点的数据一致性。
  • 目前 MHA 主要支持一主多从的架构,要搭建 MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当 master,一台充当备用 master,另外一台充当从库,因为至少需要三台服务器,出于机器成本的考虑,淘宝也在该基础上进行了改造,目前淘宝TMHA已经支持一主一从。

2. MHA集群结构说明

MHA一般至少是需要3台数据库服务器,而且额外还需要一台服务器来做为Manager端。如下图所示,一般的生产应用中,Manager是用来管理多个应用数据库集群的,它只是用来监测每个应用的master端是否故障,如果故障自动进行切换,因此资源占用并不高。
MHA集群结构说明

2-1. 服务角色

2-1-1. MHA Manager:

通常单独部署在一台独立机器上管理多个 master/slave 集群(组),每个 master/slave 集群称作一个 application,用来管理统筹整个集群。

2-1-2. MHA node:

主要是接收管理节点所发出指令的代理,代理需要运行在每一个 mysql 节点上。简单讲 node 就是用来收集从节点服务器上所生成的 bin-log 。对比打算提升为新的主节点之上的从节点的是否拥有并完成操作,如果没有发给新主节点在本地应用后提升为主节点。每个复制组内部和 Manager 之间都需要ssh实现无密码互连,只有这样,在 Master 出故障时, Manager 才能顺利的连接进去,实现主从切换功能。

2-2. MHA提供的工具脚本

MHA会提供诸多工具程序, 其常见的如下所示:
Manager节点:mha4mysql-manager-0.56-0.el6.noarch.rpm

      masterha_check_ssh:MHA 依赖的 ssh 环境监测工具;
  masterha_check_repl:MYSQL 复制环境检测工具;
  masterga_manager:MHA 服务主程序;
  masterha_check_status:MHA 运行状态探测工具;
  masterha_master_monitor:MYSQL master 节点可用性监测工具;
  masterha_master_swith:master:节点切换工具;
  masterha_conf_host:添加或删除配置的节点;
  masterha_stop:关闭 MHA 服务的工具。

Node节点:(这些工具通常由MHA Manager的脚本触发,无需人为操作)
mha4mysql-node-0.56-0.el6.noarch.rpm

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

自定义扩展:

  secondary_check_script:通过多条网络路由检测master的可用性;
  master_ip_failover_script:更新application使用的masterip;
  report_script:发送报告;
  init_conf_load_script:加载初始配置参数;
  master_ip_online_change_script;更新master节点ip地址。

2-3. MHA工作原理

MHA failover的过程
MHA failover的过程

2-3-1. MHA Failover实现方式

(1) MHA通过masterha_manger脚本启动MHA的功能.

(2) 在manager启动之前,会自动检查ssh互信(masterha_check_ssh)和主从状态(masterha_check_repl)

(3) MHA-manager 通过 masterha_master_monitor脚本(每隔ping_interval秒)

(4) masterha_master_monitor探测主库3次无心跳之后,就认为主库宕机了.

(5) 进行选主过程
	算法一: 
	读取配置文件中是否有强制选主的参数?
	candidate_master=1
	check_repl_delay=0
	算法二:
	自动判断所有从库的日志量.将最接近主库数据的从库作为新主.
	算法三:
	按照配置文件先后顺序的进行选新主.

2-4. candidate_master=1 应用场景

(1) MHA+KeepAlive VIP(早期MHA架构)
(2) 多地多中心

2-5. 数据补偿

判断主库SSH的连通性
情况一: SSH能连
调用 save_binary_logs脚本,立即保存缺失部分的binlog到各个从节点,恢复
情况二: SSH无法连接
调用 apply_diff_relay_logs 脚本,计算从库的relaylog的差异,恢复到2号从库

2-6. MHA 应用透明(vip)

1. MHA会根据配置文件调用master_ip_failover.txt脚本,实现VIP的浮动。
2. 在 /etc/mha/app01.cnf中添加该脚本
  master_ip_failover_script=/usr/local/bin/master_ip_failover
3. 第一次启动需要自己手动添加vip
 [root@db01 ~]# ifconfig eth0:1 10.211.55.85/24 
 4. 业务采用VIP,当主库down后,VIP会自己切换到选的下一个master上,这样对业务来说是透明的,因为ip都一样,业务不会知道已经切换到了另外一个库上。

2-7. MHA 故障提醒

1. MHA会根据配置文件调用/usr/local/bin/send脚本,实现有故障会主动发邮件通知。
2. 在 /etc/mha/app01.cnf中添加该脚本
 report_script=/usr/local/bin/send

2-8. 设置binlog server

1. 为了最大减少数据丢失,我们可以选取一台服务器专门负责拉取主库二进制日志,而且该binlog server不进行选主,只是为了拉去binlog
2. 在配置文件中添加binlog设置
  /etc/mha/app1.cnf 
[binlog1]
no_master=1
hostname=10.0.0.53
master_binlog_dir=/data/mysql/binlog
3. 创建该目录,并赋予对应的权限
mkdir -p /data/mysql/binlog
chown -R mysql.mysql /data/*
4. 拉取二进制日志
cd /data/mysql/binlog     -----》必须进入到自己创建好的目录
mysqlbinlog  -R --host=10.0.0.51 --user=mha --password=mha --raw  --stop-never mysql-bin.000001 &
注意:
拉取日志的起点,需要按照目前主库正在使用的binlog为起点.
5.  修改完配置文件都需要进行重启mha服务
[root@db03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
[root@db03 bin]# 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 &

3. MHA搭建配置

3-1. MHA搭建环境

为了节省虚拟机,因此规划3台虚拟机来搭建,分别为DB01和DB02及DB03,其中DB01为master,因为master压力较大,因此选DB03来安装mha manger,防止mha轻易挂掉,当然正常生产环境MHA管理节点应该是独立的一个主机,如图:
MHA环境搭建

3-1-1. MHA搭建具体实施步骤

3-1-1-1. 配置关键程序软连接
ln -s /application/mysql/bin/mysqlbinlog    /usr/bin/mysqlbinlog
ln -s /application/mysql/bin/mysql          /usr/bin/mysql
3-1-1-2. 配置互信
#创建密钥对       如果没有该命令 yum -y install openssh-clients  安装
[root@mysql-db03 ~]# ssh-keygen -t dsa -P "" -f ~/.ssh/id_dsa >/dev/null 2>&1
#发送mysql-db03公钥,包括自己
[root@mysql-db03 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.81
[root@mysql-db03 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.82
[root@mysql-db03 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.83
#发送mysql-db02公钥,包括自己
[root@mysql-db02 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.81
[root@mysql-db02 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.82
[root@mysql-db02 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.83
#发送mysql-db01公钥,包括自己
[root@mysql-db01 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.81
[root@mysql-db01 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.82
[root@mysql-db01 ~]# ssh-copy-id -i /root/.ssh/id_dsa.pub root@10.211.55.83
3-1-1-3. 检查互信是否成功
db01:
ssh 10.211.55.81 hostname
ssh 10.211.55.82 hostname
ssh 10.211.55.83 hostname
db02:
ssh 10.211.55.81 hostname
ssh 10.211.55.82 hostname
ssh 10.211.55.83 hostname
db03:
ssh 10.211.55.81 hostname
ssh 10.211.55.82 hostname
ssh 10.211.55.83 hostname
3-1-1-4. 安装软件包(所有节点)
yum install perl-DBD-MySQL -y
rpm -ivh mha4mysql-node-0.56-0.el6.noarch.rpm
3-1-1-5. 基于GTID配置主从同步:
  1. 准备环境
pkill mysqld
\rm -rf /data/mysql/data/*
\rm -rf /data/binlog/*
  1. 准备配置文件

主库db01:


cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/application/mysql/
datadir=/data/mysql/data
socket=/tmp/mysql.sock
server_id=81
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/data/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db01 [\\d]>
EOF

slave1(db02):

cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/application/mysql
datadir=/data/mysql/data
socket=/tmp/mysql.sock
server_id=82
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/data/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db02 [\\d]>
EOF

slave2(db03):

cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/application/mysql
datadir=/data/mysql/data
socket=/tmp/mysql.sock
server_id=83
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/data/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db03 [\\d]>
EOF
  1. 创建用户
useradd -s /sbin/nologin mysql
  1. 创建必须的目录
mkdir -p /data/binlog/
mkdir -p /data/mysql/data
chown -R mysql.mysql /data
  1. 初始化数据
mysqld --initialize-insecure --user=mysql --basedir=/application/mysql  --datadir=/data/mysql/data 
  1. 启动路径systemctl启动
cat >/etc/systemd/system/mysqld.service <<EOF
   [Unit]
   Description=MySQL Server
   Documentation=man:mysqld(8)
   Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
   After=network.target
   After=syslog.target
   [Install]
   WantedBy=multi-user.target
   [Service]
   User=mysql
   Group=mysql
   ExecStart=/application/mysql/bin/mysqld --defaults-file=/etc/my.cnf
   LimitNOFILE = 5000
 EOF
  1. 复制启动脚本 /etc/init.d/mysqld start启动
 cp /application/mysql/support-files/mysql.server  /etc/init.d/mysqld
 修改一下
 basedir=/application/mysql
 datadir=/data/mysql/data
  1. 启动数据库
/etc/init.d/mysqld start
  1. 构建主从:
master:81
slave:82,83

81:
grant replication slave  on *.* to repl@'10.211.55.%' identified by 'admin123';

82\83:
change master to 
master_host='10.211.55.81',
master_user='repl',
master_password='admin123' ,
MASTER_AUTO_POSITION=1;
start slave;
3-1-1-6. 在db01主库中创建mha需要的用户
grant all privileges on *.* to mha@'10.211.55.%' identified by 'mha';
3-1-1-7. Manager软件安装(db03)
yum install -y perl-Config-Tiny epel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes
rpm -ivh mha4mysql-manager-0.56-0.el6.noarch.rpm
3-1-1-7-1. 配置文件准备(db03)
	创建配置文件目录
 mkdir -p /etc/mha
	创建日志目录
 mkdir -p /var/log/mha/app1
	编辑mha配置文件
cat > /etc/mha/app1.cnf <<EOF
[server default]
manager_log=/var/log/mha/app1/manager        
manager_workdir=/var/log/mha/app1            
master_binlog_dir=/data/binlog       
user=mha                                   
password=mha                               
ping_interval=2
repl_password=admin123
repl_user=repl
ssh_user=root                               
[server1]                                   
hostname=10.211.55.81
port=3306                                  
[server2]            
hostname=10.211.55.82
port=3306
[server3]
hostname=10.211.55.83
port=3306
EOF
3-1-1-8. MHA 应用透明(vip)-db03
cp /root/master_ip_failover.txt /usr/local/bin/master_ip_failover

vim /usr/local/bin/master_ip_failover
my $vip = '10.211.55.85/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down";

[root@db03 bin]# chmod +x /usr/local/bin/master_ip_failover
[root@db03 bin]# yum install -y  dos2unix
[root@db03 bin]# dos2unix /usr/local/bin/master_ip_failover 

[root@db03 bin]# vim /etc/mha/app1.cnf 
master_ip_failover_script=/usr/local/bin/master_ip_failover

db01:手工添加vip
[root@db01 ~]# ifconfig eth0:1 10.211.55.85/24
3-1-1-9. MHA 故障提醒
[root@db03 ~]# cp -a email/* /usr/local/bin/
[root@db03 ~]# cd /usr/local/bin/
[root@db03 ]# chmod +x *

[root@db03 bin]# vim /etc/mha/app1.cnf 
report_script=/usr/local/bin/send
3-1-1-10. 额外的数据补偿(binlog_server)
找一台额外的机器,必须要有5.6以上的版本,支持gtid并开启,我们直接用的第二个slave(db03)

vim /etc/mha/app1.cnf 
[binlog1]
no_master=1
hostname=10.211.55.83
master_binlog_dir=/data/mysql/binlog

(2) 创建必要目录
mkdir -p /data/mysql/binlog
chown -R mysql.mysql /data/*

(3) 拉取主库binlog日志

cd /data/mysql/binlog     -----》必须进入到自己创建好的目录
mysqlbinlog  -R --host=10.211.55.81 --user=mha --password=mha --raw  --stop-never mysql-bin.000002 &

注意:
拉取日志的起点,需要按照目前主库正在使用的binlog为起点.
3-1-1-11. 状态检查及开启MHA(db03)
 masterha_check_ssh  --conf=/etc/mha/app1.cnf 
 masterha_check_repl  --conf=/etc/mha/app1.cnf 
 
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 &
3-1-1-12. 查看MHA状态
[root@db03 ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:10074) is running(0:PING_OK), master:10.211.55.81

4. MHA故障模拟及恢复处理

4-1. 宕掉 db01 数据库

[root@db01 ~]# /etc/init.d/mysqld stop
过了5秒后查看db02数据库看看vip是否已经飘过来了
[root@db02 ~]# ifconfig -a |grep -A3 eth0:1
eth0:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.211.55.85  netmask 255.255.255.0  broadcast 10.211.55.255
        ether 00:1c:42:06:3d:8f  txqueuelen 1000  (Ethernet)

4-2. 恢复故障

4-2-1. 启动故障节点

[root@db01 ~]# /etc/init.d/mysqld start

4-2-2. 恢复1主2从(db01)

在mha的管理日志中可以看到change master to的指令,直接把MASTER_PASSWORD密码改掉就可以直接用了
[root@db03 bin]# grep "CHANGE MASTER TO"  /var/log/mha/app1/manager
[info]  All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='xxx';

db01执行完change master to后启动slave
[root@db03 bin]# 
db01 [(none)]>CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';
db01 [(none)]>start slave;

4-2-3. 恢复配置文件(db03)

db03中恢复db01和binlog的配置文件

[server1]
hostname=10.0.0.51
port=3306
[server2]
hostname=10.0.0.52
port=3306
[server3]
hostname=10.0.0.53
port=3306
[binlog1]
no_master=1
hostname=10.211.55.83
master_binlog_dir=/data/mysql/binlog

恢复binlogserver

cd /data/mysql/binlog    
rm -rf /data/mysql/binlog/*
mysqlbinlog  -R --host=10.0.0.52 --user=mha --password=mha --raw  --stop-never mysql-bin.000001 &

4-2-4. 启动MHA

[root@db03 bin]# 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 &
[1] 16543
[root@db03 bin]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:16543) is running(0:PING_OK), master:10.0.0.52

5. 总结

  1. MHA 是一次性的,当MHA自动恢复主库成功后,MHA的监控自动会断开,需要我们把环境重新整理好,比如修复之前down掉的master,修复binlogserver,修复好配置文件,再重新启动MHA服务 ,虽然麻烦,但是它能让业务透明的情况下0-30秒内切换自动切换主库,让全年可靠性达到99.9%,还是非常理想的。
  2. MHA是单活的一个集群系统,意味着只能让可靠性增强,而不能实现proxy这种均分压力的能力,因此一般配置MHA的情况下,如果压力繁忙,还会让MHA的环境搭建中间件(atlas,mycat等),完成读写分离或者分库,分表,来分担主库的压力。
posted @ 2020-10-15 10:26  OuYangTao  阅读(314)  评论(0编辑  收藏  举报