赞
踩
MHA简介
MHA是由日本人youshimaton(原就职于DeNA,现就职于FaceBook)开发的比较成熟的MySQL高可用方案。MHA能够在30秒内实现故障切换,并能在故障切换中,最大可能的保证数据一致性。目前淘宝也正在开发相似产品TMHA,目前已支持一主一从。
MHA由MHA Manager和MHA Node组成。如下图:
MHA Manager(管理节点)
MHA Node(数据节点)
部署在所有运行MySQL的服务器上,无论是master还是slave。主要作用有三个。
Ⅰ、保存二进制日志如果能够访问故障master,会拷贝master的二进制日志
II、应用差异中继日志从拥有最新数据的slave上生成差异中继日志,然后应用差异日志。
III、清除中继日志在不停止SQL线程的情况下删除中继日志
自动故障切换过程中,MHA视图从宕机的主服务器上保存二进制日志,最大程度的保证数据不丢失
使用半同步复制,可以大大降低数据丢失的风险
目前MHA支持一主多从架构,最少三台服务,即一两从
当master出现故障时,通过对比slave之间I/O线程读取masterbinlog的位置,选取最接近的slave做为latestslave。其它slave通过与latest slave对比生成差异中继日志。在latest slave上应用从master保存的binlog,同时将latest slave提升为master。最后在其它slave上应用相应的差异中继日志并开始从新的master开始复制。
在MHA实现Master故障切换过程中,MHA Node会试图访问故障的master(通过SSH),如果可以访问(不是硬件故障,比如InnoDB数据文件损坏等),会保存二进制文件,以最大程度保证数据不丢失。MHA和半同步复制一起使用会大大降低数据丢失的危险。
案列拓扑图如下
实验思路:
实验过程
因为操作系统是centos7,所以要下载MHA 0.57版本 系统:centos 7.6
在三台MySQL 节点上分别安装数据库,MySQL版本请使用5.6.36,cmake版本请使用2.8.6。下面只在Mysql1上面做演示,安装过程如下。
软件包直接下载即可
链接:https://pan.baidu.com/s/1loTBbGw88a9yv5MOi98ZnQ
提取码:owxk
[root@localhost ~]# hostnamectl set-hostname MHA
[root@localhost ~]# su
[root@mha ~]# iptables -F
[root@mha ~]# setenforce 0
[root@localhost ~]# hostnamectl set-hostname master
[root@localhost ~]# su
[root@master ~]# iptables -F
[root@master ~]# setenforce 0
[root@localhost ~]# hostnamectl set-hostname slave
[root@localhost ~]# su
[root@slave ~]# iptables -F
[root@slave ~]# setenforce 0
#作为主备
[root@tom03 ~]# iptables -F
[root@tom03 ~]# setenforce 0
[root@master~]# yum install ncurses-devel gcc-c++ gcc perl-Module-Install -y
#把安装包移动到家目录
[root@master ~]# ls
anaconda-ks.cfg mha4mysql-manager-0.57.tar.gz ruby-2.4.1.tar.gz 图片 桌面
cmake-2.8.6 mha4mysql-node-0.57.tar.gz 公共 文档
cmake-2.8.6.tar.gz mysql-5.6.36 模板 下载
initial-setup-ks.cfg mysql-5.6.36.tar.gz 视频 音乐
#进行解压camke
[root@master ~]# tar zxvf cmake-2.8.6.tar.gz
#切换到cmake目录
[root@master ~]# cd cmake-2.8.6/
#执行脚本配置文件
[root@master cmake-2.8.6]# ./configure
#编译安装
[root@master cmake-2.8.6]# gmake && gmake install
#解压mysql [root@master ~]# tar zxvf mysql-5.6.36.tar.gz [root@master ~]# cd mysql-5.6.36/ [root@master mysql-5.6.36]# cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DDEFAULT_CHARSET=utf8 \ -DDEFAULT_COLLATION=utf8_general_ci \ -DWITH_EXTRA_CHARSETS=all \ -DSYSCONFDIR=/etc #编译 [root@master mysql-5.6.36]# make [root@master mysql-5.6.36]# make install #把主配置文件复制到etc/my.cf [root@master mysql-5.6.36]# cp support-files/my-default.cnf /etc/my.cnf #启动脚本 [root@master mysql-5.6.36]# cp support-files/mysql.server /etc/rc.d/init.d/mysqld #增加执行权限 [root@localhost mysql-5.6.36]# chmod +x /etc/rc.d/init.d/mysqld #将mysql加入到chkconfig系统表中 [root@master mysql-5.6.36]# chkconfig --add mysqld #配置环境变量便于系统所识别 [root@master mysql-5.6.36]# echo "PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile #使环境变量生效 [root@master mysql-5.6.36]# source /etc/profile #设置组 [root@master mysql-5.6.36]# groupadd mysql [root@master mysql-5.6.36]# useradd -M -s /sbin/nologin mysql -g mysql [root@master mysql-5.6.36]# chown -R mysql.mysql /usr/local/mysql/ #创建数据文件存放位置 [root@master mysql-5.6.36]# mkdir -p /data/myssql #初始化数据库 /usr/local/mysql/scripts/mysql_install_db \ --basedir=/usr/local/mysql \ --datadir=/usr/local/mysql/data \ --user=mysql
[root@master mysql-5.6.36]# vim /etc/my.cnf [mysqld]段落添加 server-id =1 //表示唯一id log_bin=master-bin //主服务器日志文件 log-slave-updates=true //从服务器更新二进制日志 #配置从从服务器 [root@slave ~]# vim /etc/my.cnf [mysqld]段落添加 server-id = 2 //不能与主服务器一样 log_bin = master-bin relay-log = relay-log-bin //开启中继日志 relay-log-index = slave-relay-bin.index //定义relay-log的 位置名称 #另一台从服务器 [root@tom03 ~]# vim /etc/my.cnf #添加 server-id=3 log_bin=master-bin relay-log=relay-log-bin relay-log-index=slave-relay-bin.index #设置所执行命令让系系统所识别三台分别做软连接 ln -s /usr/local/mysql/bin/mysql /usr/sbin/ ln -s /usr/local/mysql/bin/mysqlbinlog /usr/sbin/
/usr/local/mysql/bin/mysqld_safe --user=mysql &
#查看端口
[root@master mysql-5.6.36]# netstat -ntap | grep 3306
tcp6 0 0 :::3306 :::* LISTEN 120279/mysqld
1.Mysql主从配置相对简单,一个是从库同步使用,另一个是manager使用。(三台都配)
#登录数据库
mysql -uroot -p
Enter password: 密码直接回车
grant replication slave on *.* to 'myslave'@'20.0.0.%' identified by '123456';
#配置给manager的监管权限
grant all privileges on *.* to 'mha'@'20.0.0.%' identified by 'manager';
#刷新数据库
flush privileges;
grant all privileges on *.* to 'mha'@'master' identified by 'manager';
grant all privileges on *.* to 'mha'@'slave' identified by 'manager';
grant all privileges on *.* to 'mha'@'tom03' identified by 'manager';
#刷新数据库
flush privileges;
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 1485 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
change master to master_host='20.0.0.41',master_user='myslave',master_password='123',master_log_file='master-bin.000001',master_log_pos=1485;
flush privileg;
#开启slave
start slave;
show slave status\G;
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
必须设置两个从库为只读模式:
set global read_only=1;
#在刷新
flush privileges;
#创建niu数据据 mysql> create database niu; #使用niu数据库 mysql> use niu; #创建tt表 mysql> create table tt (id int(3),name char(10)); #插入表结构数据 mysql> insert into tt (id,name) values (1,'zhangsan'),(3,'lisi'); #查询表信息 mysql> select * from tt; +------+----------+ | id | name | +------+----------+ | 1 | zhangsan | | 3 | lisi | +------+----------+ 2 rows in set (0.00 sec) #从数据库查看 #显示所有数据库 可以看到有niu库 mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | niu | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec) #进入数据库niu mysql> use niu; #可以看到数据都同步成功 mysql> select * from tt; +------+----------+ | id | name | +------+----------+ | 1 | zhangsan | | 3 | lisi | +------+----------+ rows in set (0.00 sec) #同步成功
yum install epel-release --nogpgcheck -y
yum install -y perl-DBD-MySQL \ //连接数据库的环境
perl-Config-Tiny \ //配置文件
perl-Log-Dispatch \ //日志
perl-Parallel-ForkManager \ //管理框架
perl-ExtUtils-CBuilder \ //构建
perl-ExtUtils-MakeMaker \
perl-CPAN //函数库
[root@master ~]# tar zxvf mha4mysql-node-0.57.tar.gz
[root@master ~]# cd mha4mysql-node-0.57/
[root@master mha4mysql-node-0.57]# perl Makefile.PL
[root@master mha4mysql-node-0.57]# make && make install
#解压manager包
[root@mha ~]# tar zxvf mha4mysql-manager-0.57.tar.gz
[root@mha ~]# cd mha4mysql-manager-0.57/
[root@mha mha4mysql-manager-0.57]# perl Makefile.PL
[root@mha mha4mysql-manager-0.57]# make
[root@mha mha4mysql-manager-0.57]# make install
masterha_check_ssh检查MHA的SSH配置状况
masterha_check_repl检查MySQL复制状况
masterha_manger启动manager的脚本
masterha_check_status检测当前MHA运行状态
masterha_master_monitor检测master是否宕机
masterha_master_switch控制故障转移(自动或者手动)
masterha_conf_host添加或删除配置的server信息
masterha_stop关闭manager
save_binary_logs保存和复制master的二进制日志
apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的slave
filter_mysqlbinlog去除不必要的ROLLBACK事件(MHA已不再使用这个工具)
purge_relay_logs清除中继日志(不会阻塞SQL线程)
具体如下
[root@mha bin]# ssh-keygen -t rsa //一路回车 The key's randomart image is: +---[RSA 2048]----+ |o+=Oo*o . .. ooo| | oo.O.=. o ... .| | o+ = +. o E. . | |.. +++..o o | |+o. o.+.S o | |oo.o + o | |. . . . . | | . | | | +----[SHA256]-----+ #会生成无密码的密钥对 #.ssh就是生成的密钥对 [root@mha ~]# ls -a /root/.ssh . .. id_rsa id_rsa.pub #把密钥对推给三个服务器 [root@mha ~]# ssh-copy-id 20.0.0.41 #创建非对称密码对 ..省略内容 Are you sure you want to continue connecting (yes/no)? yes #输入yes ...省略..... root@20.0.0.41's password: #输入对方的密码 Permission denied, please try again. root@20.0.0.41's password: #再次输入密码 ##相同的方法建立其他从服务器 [root@mha ~]# ssh-copy-id 20.0.0.43 [root@mha ~]# ssh-copy-id 20.0.0.42
[root@master mha4mysql-node-0.57]# ssh-keygen -t rsa
[root@master mha4mysql-node-0.57]# ssh-copy-id 20.0.0.42
[root@master mha4mysql-node-0.57]# ssh-copy-id 20.0.0.43
[root@slave mha4mysql-node-0.57]# ssh-keygen -t rsa
[root@slave mha4mysql-node-0.57]# ssh-copy-id 20.0.0.43
[root@slave mha4mysql-node-0.57]# ssh-copy-id 20.0.0.41
[root@tom03 mha4mysql-node-0.57]# ssh-keygen -t rsa
[root@tom03 mha4mysql-node-0.57]# ssh-copy-id 20.0.0.41
[root@tom03 mha4mysql-node-0.57]# ssh-copy-id 20.0.0.42
[root@mha ~]# cd mha4mysql-manager-0.57/samples/scripts/ [root@mha scripts]# ls master_ip_failover power_manager master_ip_online_change send_report #把scipts的全部脚本文件复制到/usr/local/bin让系统所能识别 [root@mha scripts]# cp -ra /root/mha4mysql-manager-0.57/samples/scripts /usr/local/bin [root@mha ~]# cd /usr/local/bin/scripts/ [root@mha scripts]# ll 总用量 32 -rwxr-xr-x. 1 nginx nginx 3648 5月 31 2015 master_ip_failover //自动切换VIP管理脚本【虚拟IP管理脚本】 -rwxr-xr-x. 1 nginx nginx 9870 5月 31 2015 master_ip_online_change //在线切换时vip的管理 -rwxr-xr-x. 1 nginx nginx 11867 5月 31 2015 power_manager //故障发生后关闭主机的脚本 -rwxr-xr-x. 1 nginx nginx 1360 5月 31 2015 send_report //因故障切换后发送报警的脚本 #使用脚本管理VIP [root@mha scripts]# cp /usr/local/bin/scripts/master_ip_failover /usr/local/bin/
[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 = '20.0.0.200'; #设置虚拟IP my $brdc = '20.0.0.255'; #设置广播地址 my $ifdev = 'ens33'; #物理网卡名称 my $key = '1'; my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip"; #开启逻辑子接口IP my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down"; #关闭接口 my $exit_code = 0; #退出状态码 #my $ssh_stop_vip = "/usr/sbin/ip addr del $vip/24 dev $ifdev label $ifdev:$key"; 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; } 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 \"`; } # 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"; }
[root@mha scripts]# cp master_ip_online_change /usr/local/bin/ [root@mha scripts]# cp send_report /usr/local/ [root@mha scripts]# mkdir /etc/masterha #复制配置文件到创建的目录 [root@mha scripts]# cp /root/mha4mysql-manager-0.57/samples/conf/app1.cnf /etc/masterha/ #修改配置文件 [root@mha log]# vim /etc/masterha/app1.cnf #删除原有内容并修改 [server default] manager_workdir=/usr/log/masterha/app1.log manager_log=/var/log/masterha/app1/manager.log master_binlog_dir=/usr/local/mysql/data master_ip_failover_script=/usr/local/bin/master_ip_failover master_ip_online_change_script=/usr/local/bin/master_ip_online_change password=manager ping_interval=1 remote_workdir=/tmp repl_password=123 repl_user=myslave report_script=/usr/local/send_report secondary_check_script=/usr/local/bin/masterha_secondary_check -s 20.0.0.42 -s 20.0.0.43 shutdown_script="" ssh_user=root user=mha [server1] hostname=20.0.0.41 port=3306 [server2] hostname=20.0.0.42 port=3306 candidate_master=1 check_repl_delay=0 [server3] hostname=20.0.0.43 port=3306
[server default] manager_workdir=/usr/log/masterha/app1.log ## manager工作目录 manager_log=/var/log/masterha/app1/manager.log ## manager日志 master_binlog_dir=/usr/local/mysql/data ## master保存binlog的位置,这里的路径要与master里配置的binlog路径一致,以便mha能找到 master_ip_failover_script=/usr/local/bin/master_ip_failover ## 设置自动failover时候切换脚本 master_ip_online_change_script=/usr/local/bin/master_ip_online_change ## 设置手动切换时候的脚本 password=manager ## 设置mysql中root用户的密码,这个密码是前文中创建监控用户的密码 user=mha ## 设置监控用户root ping_interval=1 ## 设置监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应的时候自动进行railover remote_workdir=/tmp ## 远端mysql在发生切换时binlog的保存位置 repl_password=123 ## 设置复制用户的密码 repl_user=myslave ## 设置复制用户的用户名 report_script=/usr/local/send_report ## 设置发生切换后发送的报警脚本 secondary_check_script=/usr/local/bin/masterha_secondary_check -s 192.168.50.133 -s 192.168.50.134 shutdown_script="" ## 设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机防止发生脑裂,这里没有使用) ssh_user=root ## 设置ssh的登录用户名 [server2] candidate_master=1 ## 设置为候选master,如果设置该参数以后,发生主从切换以后会将此从库提升为主库,即使这个主库 check_repl_delay=0 ## 默认清空下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slaver作为一个新的master
[root@mha ~]# masterha_check_ssh -conf=/etc/masterha/app1.cnf Sat Aug 29 20:35:03 2020 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping. Sat Aug 29 20:35:03 2020 - [info] Reading application default configuration from /etc/masterha/app1.cnf.. Sat Aug 29 20:35:03 2020 - [info] Reading server configuration from /etc/masterha/app1.cnf.. Sat Aug 29 20:35:03 2020 - [info] Starting SSH connection tests.. Sat Aug 29 20:35:05 2020 - [debug] Sat Aug 29 20:35:03 2020 - [debug] Connecting via SSH from root@20.0.0.41(20.0.0.41:22) to root@20.0.0.42(20.0.0.42:22).. Sat Aug 29 20:35:04 2020 - [debug] ok. Sat Aug 29 20:35:04 2020 - [debug] Connecting via SSH from root@20.0.0.41(20.0.0.41:22) to root@20.0.0.43(20.0.0.43:22).. Sat Aug 29 20:35:05 2020 - [debug] ok. Sat Aug 29 20:35:06 2020 - [debug] Sat Aug 29 20:35:04 2020 - [debug] Connecting via SSH from root@20.0.0.43(20.0.0.43:22) to root@20.0.0.41(20.0.0.41:22).. Sat Aug 29 20:35:05 2020 - [debug] ok. Sat Aug 29 20:35:05 2020 - [debug] Connecting via SSH from root@20.0.0.43(20.0.0.43:22) to root@20.0.0.42(20.0.0.42:22).. Sat Aug 29 20:35:06 2020 - [debug] ok. Sat Aug 29 20:35:06 2020 - [debug] Sat Aug 29 20:35:04 2020 - [debug] Connecting via SSH from root@20.0.0.42(20.0.0.42:22) to root@20.0.0.41(20.0.0.41:22).. Sat Aug 29 20:35:04 2020 - [debug] ok. Sat Aug 29 20:35:04 2020 - [debug] Connecting via SSH from root@20.0.0.42(20.0.0.42:22) to root@20.0.0.43(20.0.0.43:22).. Sat Aug 29 20:35:05 2020 - [debug] ok. Sat Aug 29 20:35:06 2020 - [info] All SSH connection tests passed successfully.
#执行命令进行检查
masterha_check_repl -conf=/etc/masterha/app1.cnf
MySQL Replication Health is OK.
ps:结果不正确是is not OK!
[root@master ~]# /sbin/ifconfig ens33:1 20.0.0.200/24
nohup masterha_manager --conf=/etc/masterha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /var/log/masterha/app1/manager.log 2>&1 &
PS:有的时候会提示“没有这个文件或目录”是因为没有建立日志存放目录,所以我们需要去手动在/var/log/目录下创建masterha目录,在其中再创建app1目录
#创建目录
[root@localhost ~]# mkdir -p /var/log/masterha/app1
--remove_dead_master_conf 该参数代表发生主从切换后,老的主库ip将会从配置文件中移除
--manager_log 日志存放位置
--ignore_last_failover 在缺省情况下,如果MHA检测到连续发生宕机,且两次宕机时间不足8小时的话,则不会进行Failover,之所以这样是为了避免ping-pong效应。该参数代表忽略上次MHA触发切换产生的文件,默认情况下,MHA发生切换后会在日志记录,也就是上面设置的日志app1.failover.complete文件,下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后收到删除该文件,为了方便,这里设置为-ignore_last_failover
masterha_check_status --conf=/etc/masterha/app1.cnf
app1 (pid:86379) is running(0:PING_OK), master:20.0.0.41
ens33:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 20.0.0.200 netmask 255.255.255.0 broadcast 20.0.0.255
ether 00:0c:29:84:c1:e3 txqueuelen 1000 (Ethernet)
#查看master的端口
[root@master ~]# netstat -ntap | grep 3306
tcp6 0 0 :::3306 :::* LISTEN 112987/mysqld
tcp6 0 0 20.0.0.41:3306 20.0.0.43:52352 ESTABLISHED 112987/mysqld
tcp6 0 0 20.0.0.41:3306 20.0.0.42:39738 ESTABLISHED 112987/mysqld
tcp6 0 0 20.0.0.41:3306 20.0.0.44:59948 ESTABLISHED 112987/mysqld
#假如我们把进程给干死
[root@master ~]# pkill -9 mysql 飘逸地址会不会转移到另外一台服务器
再次查看端口服务已经关闭
以上。我们的实验已经圆满完成。
如有疑问或者建议大家可以多多讨论呐~(~ ̄▽ ̄)~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。