MySQL高可用-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 node 运行在每台 MySQL 服务器上(master/slave/manager),它通过监控具备解析和清理 logs 功能的脚本来加快故障转移的。
在 MHA 自动故障切换过程中,MHA 试图从宕机的主服务器上保存二进制日志,最大程度的保证数据的不丢失,但这并不总是可行的。例如,如果主服务器硬件故障或无法通过 ssh 访问,MHA 没法保存二进制日志,只进行故障转移而丢失了最新的数据。使用 MySQL 5.5 的半同步复制,可以大大降低数据丢失的风险。MHA 可以与半同步复制结合起来。如果只有一个 slave 已经收到了最新的二进制日志,MHA 可以将最新的二进制日志应用于其他所有的 slave 服务器上,因此它们可以彼此保证数据一致性。
目前 MHA 主要支持一主多从的架构,要搭建 MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当 master,一台充当备用 master,另外一台充当从库,因为至少需要三台数据库,出于机器成本的考虑,淘宝也在该基础上进行了改造,目前淘宝 TMHA 已经支持一主一从。
MHA 特点
(1)10-30s 实现 master failover(9-12s 可以检测到主机故障,7-10s 可以关闭主机避免 SB,在用很短的时间应用差异日志)
(2) 部署简单,无需对现有 M-S 结构做任何改动(至少 3 台,保证切换后仍保持 M-S 结构)
(3) 支持手动在线切换(主机硬件维护),downtime 几乎很短 0.5-2s
(4) 保证故障切换后多从库数据的一致性
(5) 完全自动化的 failover 及快速复制架构恢复方案(一主多从)
(6) 恢复过程包括:选择新主库、确认从库间 relaylog 差异、新主库应用必要语句、其他从库同步差异语句、重新建立复制连接
优点
(1)出同步最成功的一台从服务器(也就是与主服务器数据最接近的那台从服务器)自动切换成主服务器;
(2)如果主机还能够访问,从主服务器上找回最新从机与主机间的数据差异;
(3)在每一台从服务器上操作,确定他们缺少哪些 events,并分别进行补充;
(4)将最新的一台从服务器提升为主服务器后,将其它从服务器重新指向新的主服务器;
缺点
(1)当群集内的数据库进行故障转移时,对外提供服务的虚拟 IP 也进行转移;
(2)MHA 管理进程需要以后台守护进程的方式运行,并有监控机制保证 MHA 管理进程的正常运行;
(3)有监控机制保证当主机出现故障时,MHA 能确定进行成功的 Failover;
(4)当故障主机恢复后,能重新回到群集中,并成为新的 Slave,自动实现重新同步;
(5)由于主机和从机上备份策略不同,进行故障转移后,自动调整 cron 中的调度(例如全备份);
MHA 集群架构图
上图示意了如果通过 MHA Manager 管理多组主从复制。可以将 MHA 工作原理总结为:
(1)从宕机崩溃的 master 保存二进制日志事件(binlog events);
(2)识别含有最新更新的 slave;
(3)应用差异的中继日志(relay log)到其他 slave;
(4)应用从 master 保存的二进制日志事件(binlog events)
(5)提升一个 slave 为新 master;
(6)使其他的 slave 连接新的 master 进行复制;
MHA 软件由两部分组成,Manager 工具包和 Node 工具包,说明:
Manager 工具包主要包括以下几个工具
masterha_check_ssh : 检查 MHA 的 SSH 配置状况
masterha_check_repl: 检查 MySQL 复制状况
masterha_manger: 启动 MHA
masterha_check_status: 检测当前 MHA 运行状态
masterha_master_monitor: 检测 master 是否宕机
masterha_master_switch: 控制故障转移(自动或者手动)
masterha_conf_host: 添加或删除配置的 server 信息
Node 工具包(这些工具通常由 MHA Manager 的脚本触发,无需人为操作)主要包括以下几个工具:
save_binary_logs: 保存和复制 master 的二进制日志
apply_diff_relay_logs: 识别差异的中继日志事件并将其差异的事件应用于其他的 slave
filter_mysqlbinlog: 去除不必要的 ROLLBACK 事件(MHA 已不再使用这个工具)
purge_relay_logs: 清除中继日志(不会阻塞 SQL 线程)
二、安装部署 MHA
1.环境配置
| 角色 | IP 地址 | 主机名 | Server ID | 类型 |
|---|---|---|---|---|
| Master | 192.168.199.134 | DB1 | 1 | 写入 |
| Candicate master | 192.168.199.212 | DB2 | 2 | 读 |
| Slave | 192.168.199.233 | DB3 | 3 | 读 |
| Monitor host,Manager | 192.168.199.180 | monitor | 监控集群组 |
其中 master 对外提供写服务,备选 master 提供读服务,slave 也提供相关的读服务,一旦 master 宕机,将会把备选 master 提升为新的 master,slave 指向新的 master。
修改 hosts 文件(4 台机器都需要添加)
192.168.199.134 db1
192.168.199.212 db2
192.168.199.233 db3
192.168.199.180 monitor
所需软件及版本
| 软件 | 版本 |
|---|---|
| 系统版本 | CentOS Linux release 7.2.1511 |
| 系统内核 | 3.10.0-327.el7.x86_64 |
| mha4mysql-manager | 0.56 |
| mha4mysql-node | 0.56 |
| MySQL | 5.7.18 |
| keepalived | 1.3.5 |
| sysbench | 1.0.6 |
| daemontools | 0.76 |
2.安装 MHA node
在所有的 MySQL 服务器上安装
(1) 安装 MHA node 所需要的 perl 模块
在 MySQL 服务器上安装 MHA node 所需要的 perl 模块
# yum install perl-DBD-MySQL -y
# yum install -y perl-devel
# yum install -y perl-CPAN
(2) 在所有的节点上安装 mha node
# wget -P /usr/local/ https://downloads.mariadb.com/MHA/mha4mysql-node-0.56.tar.gz
# tar zxf mha4mysql-node-0.56.tar.gz
# cd mha4mysql-node-0.56
# perl Makefile.PL
# make && make install
安装后会在/usr/bin/下生成一下脚本文件:
Node 脚本说明:(这些工具通常由 MHA Manager 的脚本触发,无需人为操作)
save_binary_logs //保存和复制 master 的二进制日志
apply_diff_relay_logs //识别差异的中继日志事件并将其差异的事件应用于其他的 slave
filter_mysqlbinlog //去除不必要的 ROLLBACK 事件(MHA 已不再使用这个工具)
purge_relay_logs //清除中继日志(不会阻塞 SQL 线程)
3.安装 MHA Manager (monitor 机器)
MHA Manager 中主要包括了几个管理员的命令行工具,例如 masterha_manager、masterha_master_switch 等。MHA Manager 也是依赖于一些 perl 模块。
(1) 安装 MHA Node 软件包
在 MHA Manager 的主机上也要安装 MHA Node
安装步骤参考上面
(2) 安装 MHA Mnager 软件
安装 MHA Manager 所需要的 Perl 模块:
# yum install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes -y
安装 MHA Manager 软件包:
# wget -P /usr/local/ https://downloads.mariadb.com/MHA/mha4mysql-manager-0.56.tar.gz
# tar zxf mha4mysql-manager-0.56.tar.gz
# perl Makefile.PL
# make
# make install

安装后会在/usr/bin/下生成以下脚本文件:
4.配置 SSH 无密码登录验证
MHA 环境需要 3 台主机互相信任,实现 3 台机器免密码登录
(使用 key 登录,工作中常用,最好不要禁掉密码登录,如果禁了,可能会有问题)
(1) 在 manager 上配置到所有 Node 节点的无密码验证
# ssh-keygen
# ssh-copy-id -i root@db1
# ssh-copy-id -i root@db2
# ssh-copy-id -i root@db3
(2) 在 MHA Node DB1 上
# ssh-keygen
# ssh-copy-id -i root@db2
# ssh-copy-id -i root@db3
(3) 在 MHA Node DB2 上
# ssh-keygen
# ssh-copy-id -i root@db1
# ssh-copy-id -i root@db3
(4) 在 MHA Node DB3 上
# ssh-keygen
# ssh-copy-id -i root@db1
# ssh-copy-id -i root@db2
5.搭建主从复制环境
主从我们是使用 GTID + ROW 的方式进行配置
(1) 在 master 上执行备份
# mysqldump -uroot -p --master-data=2 --single-transaction -R --triggers -A > db1.sql
(2) 在 master 上创建复制用户
mysql> grant replication slave on *.* to 'repl'@'192.168.199.%' identified by 'unixfbi';
mysql> flush privilges;
(3) 将备份复制到 db2 和 db3 上
# scp db1.sql root@db2:~/
# scp db1.sql root@db3:~/
(4) 在 DB2 上搭建备库
# mysql -uroot -p < db1.sql
mysql> CHANGE MASTER TO
MASTER_HOST='192.168.199.134',
MASTER_USER='repl',
MASTER_PASSWORD='unixfbi',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1;
mysql> start slave;
查看同步状态
(5) 在 DB3 上搭建备库
# mysql -uroot -p < db1.sql
mysql> CHANGE MASTER TO
MASTER_HOST='192.168.199.134',
MASTER_USER='repl',
MASTER_PASSWORD='unixfbi',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1;
mysql> start slave;
查看复制状态:
(6) slave 服务器设置 read only
将每个 slave 设置为 read only:
从库对外提供读操作,这里将 read_only 设置为 1
# mysql -uroot -punixfbi -e "set global read_only=1;"
(7) 创建监控用户
整个复制集群已经搭建完毕,这时还需要创建监控所需要的用户,在 DB1 上执行:
mysql> grant all privileges on *.* to root@'192.168.199.%' identified by 'unixfbi';
mysql> flush privileges;
至此,MHA 软件已经基本安装完毕。下面开始配置 MHA 软件。
6.配置 MHA (在 monitor 机器)
配置 MHA 的大体步骤如下
(1) 创建 MHA 工作目录,并且创建相关配置文件
创建数据文件目录
# mkdir -p /usr/local/masterha/app1
创建配置文件目录
# mkdir -p /etc/masterha
# cp /usr/local/mha4mysql-manager-0.56/samples/conf/app1.cnf /etc/masterha/
修改/etc/masterha/app1.conf 配置文件,修改后内容为:
# cat /etc/masterha/app1.cnf
[server default]
manager_workdir=/usr/local/masterha/app1 #该目录为 mha manager 产生相关状态文件全路径数据目录
manager_log=/var/log/masterha/app1/manager.log #设置 manager 的日志
master_binlog_dir=/data/mysql/mysql3306/logs/ 设置 master 保存 binlog 的位置,以便 MHA 可以找到 master 的日志,我这里的也就是 mysql 的数据目录
master_ip_failover_script= /usr/local/bin/master_ip_failover # 设置自动 failover 时候的切换脚本
master_ip_online_change_script= /usr/local/bin/master_ip_online_change # 设置手动切换时候的切换脚本
password=unixfbi # 设置 mysql 中 root 用户的密码,这个密码是前文中创建监控用户的那个密码
user=root # 设置监控用户 root
ping_interval=1 # 设置监控主库,发送 ping 包的时间间隔,默认是 3 秒,尝试三次没有回应的时候自动进行 railover
remote_workdir=/usr/local/masterha/app1 # MHA node 上工作目录的全路径名。如果不存在,MHA node 会自动创建,如果不允许创建,MHA Node 自动异常退出。这个配置不是必须配置的,默认目录是在/var/tmp
repl_password=unixfbi #设置复制用户的密码
repl_user=repl #设置复制环境中的复制用户名
report_script=/usr/local/bin/send_report # 设置发生切换后发送的报警的脚本
secondary_check_script= /usr/local/bin/masterha_secondary_check -s db2 -s db1 --user=root --master_host=db1 --master_ip=192.168.199.134 --master_port=3306 # 一旦 MHA 到 db1 的监控之间出现问题,MHA Manager 将会尝试从 db2 登录到 db1
shutdown_script="" # 设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机放在发生脑裂,这里没有使用)
ssh_user=root # 设置 ssh 的登录用户名
[server1]
hostname=db1
port=3306
[server2]
hostname=db2
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=db3
port=3306
(2) 设置 relay log 清除方式(在每个 slave 上)
# mysql -uroot -punixfbi -e "set global relay_log_purge=0"
MHA 在发生切换的过程中,从库的恢复过程中依赖于 relay log 的相关信息,所以这里要将 relay log 的自动清除设置为 OFF,采用手动清除 relay log 的方式。在默认情况下,从服务器上的中继日志会在 SQL 线程执行完毕后被自动删除。但是在 MHA 环境中,这些中继日志在恢复其他从服务器时可能会被用到,因此需要禁用中继日志的自动删除功能。定期清除中继日志需要考虑到复制延时的问题。在 ext3 的文件系统下,删除大的文件需要一定的时间,会导致严重的复制延时。为了避免复制延时,需要暂时为中继日志创建硬链接,因为在 linux 系统中通过硬链接删除大文件速度会很快。(在 mysql 数据库中,删除大表时,通常也采用建立硬链接的方式)
(3) 设置定期清理 relay 脚本
使用如下命令设置 crontab 来定期清理 Relay Log:
# cat purge_relay_log.sh
#!/bin/bash
user=root
passwd=unixfbi
port=3306
log_dir='/data/masterha/log'
work_dir='/data'
purge='/usr/local/bin/purge_relay_logs'
if [ ! -d $log_dir ]
then
mkdir $log_dir -p
fi
$purge --user=$user --password=$passwd --disable_relay_log_purge --port=$port --workdir=$work_dir >> $log_dir/purge_relay_logs.log 2>&1
设置定时任务
# crontab -l
0 4 * * * /bin/bash /root/purge_relay_log.sh
参数说明
--user mysql //用户名
--password mysql //密码
--port //端口号
--workdir //指定创建 relay log 的硬链接的位置,默认是/var/tmp,由于系统不同分区创建硬链接文件会失败,故需要执行硬链接具体位置,成功执行脚本后,硬链接的中继日志文件被删除
--disable_relay_log_purge //默认情况下,如果 relay_log_purge=1,脚本会什么都不清理,自动退出,通过设定这个参数,当 relay_log_purge=1 的情况下会将 relay_log_purge 设置为 0。清理 relay log 之后,最后将参数设置为 OFF。
purge_relay_logs 脚本删除中继日志不会阻塞 SQL 线程。下面我们手动执行看看什么情况:
[root@db2~]# purge_relay_logs --user=root --password=unixfbi --port=3306 --disable_relay_log_purge --workdir=/data/
2017-07-26 17:05:28: purge_relay_logs script started.
Found relay_log.info: /data/mysql/mysql3306/data/relay-log.info
Removing hard linked relay log files relay-bin* under /data/.. done.
Current relay log file: /data/mysql/mysql3306/data/relay-bin.000004
Archiving unused relay log files (up to /data/mysql/mysql3306/data/relay-bin.000003) ...
Creating hard link for /data/mysql/mysql3306/data/relay-bin.000003 under /data//relay-bin.000003 .. ok.
Creating hard links for unused relay log files completed.
Executing SET GLOBAL relay_log_purge=1; FLUSH LOGS; sleeping a few seconds so that SQL thread can delete older relay log files (if it keeps up); SET GLOBAL relay_log_purge=0; .. ok.
Removing hard linked relay log files relay-bin* under /data/.. done.
2017-07-26 17:05:31: All relay log purging operations succeeded.
7.检查 SSH 的配置
检查 MHA Manager 到所有 MHA Node 的 SSH 连接状态:
# masterha_check_ssh --conf=/etc/masterha/app1.cnf
# masterha_check_ssh --conf=/etc/masterha/app1.cnf
Wed Jul 26 17:08:46 2017 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Wed Jul 26 17:08:46 2017 - [info] Reading application default configurations from /etc/masterha/app1.cnf..
Wed Jul 26 17:08:46 2017 - [info] Reading server configurations from /etc/masterha/app1.cnf..
Wed Jul 26 17:08:46 2017 - [info] Starting SSH connection tests..
Wed Jul 26 17:08:49 2017 - [debug]
Wed Jul 26 17:08:47 2017 - [debug] Connecting via SSH from root@db2(192.168.199.212:22) to root@db1(192.168.199.134:22)..
Wed Jul 26 17:08:48 2017 - [debug] ok.
Wed Jul 26 17:08:48 2017 - [debug] Connecting via SSH from root@db2(192.168.199.212:22) to root@db3(192.168.199.233:22)..
Wed Jul 26 17:08:48 2017 - [debug] ok.
Wed Jul 26 17:08:49 2017 - [debug]
Wed Jul 26 17:08:47 2017 - [debug] Connecting via SSH from root@db3(192.168.199.233:22) to root@db1(192.168.199.134:22)..
Wed Jul 26 17:08:48 2017 - [debug] ok.
Wed Jul 26 17:08:48 2017 - [debug] Connecting via SSH from root@db3(192.168.199.233:22) to root@db2(192.168.199.212:22)..
Wed Jul 26 17:08:48 2017 - [debug] ok.
Wed Jul 26 17