参考地址:mysql 高可用架构之 MHA,haproxy 实现读写分离详解
实验步骤:
ssh 证书户信任(ssh 的密钥验证)
ABB 架构
安装 mha_manager 、 mha_node
测试
IP 地址规划:
Mysql_manager(10.211.55.23)—需要是 64 位的系统
MySQL_A(10.211.55.20)
MySQL_B1(10.211.55.21)
MySQL_B2(10.211.55.22)
ssh 证书互信脚本---每台机器上都要操作
使用 ssh-kegen 生成公私钥(每台服务器上),下面是批量执行脚本:
#!/bin/bash
for i in 0 1 2 3
do
ssh-copy-id -i /root/.ssh/id_rsa.pub 10.211.55.20$i
done
ABB 搭建
Mysql 的安装(感觉下面的安装方法比较简单):
wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm rpm -ivh mysql-community-release-el7-5.noarch.rpm yum install mysql-community-server service mysqld restart mysql -u root mysql> set password for 'root'@'localhost' =password('youpassword');
所有的机器初始化 MySQL,设置 ABB 架构:
MYSQL_A(20)上的操作:
vim /etc/my.cnf
server_id=1 //设置优先级最高
log_bin=binlog //开启 binlog 日志
log_biin=binlog.index
注意:MYSQL_B1、MYSQL_B2 上的操作同 mysql_a 只是注意 server_id 的不同!
设置用户
在 msyql_a(20)中:因为前面已经开启二进制日志了,所以其他机器也能学到赋权语句!!故其他机器就不用再赋权了!
//给mha_manager用,因为其在failover时需要登陆上来,并且拷贝binlog到所有的slave上去 jdata1> grant all on *.* to 'root'@'%' identified by 'youpassword'; //复制专用用户 jdata1> grant replication slave on *.* to 'sky'@'%' identified by 'youpassword'; //刷新权限 jdata1> flush privileges; //看一下binlog日志到第几个文件了 jdata1> show master status\G
在 mysql_b1(21)中:
mysql> stop slave; mysql> change master to master_host='10.211.55.20',master_user='sky',master_password='yourpassword',master_log_file='mysql-bin.000003'; mysql> reset slave; (注意:如果之前因为同步数据的时候sql执行错误,这里要清除掉) mysql> start slave; mysql> show slave status\G //查看复制线程状态
在 mysql_b2(22)做 21 上同样的操作!
安装配置启动 mha_manager、mha_node
manager 机器上(23):cd /root/zing (mha4mysql-node 和 mha4mysql-manager rpm 文件,要保存这 2 个文件,这 2 个东西不好找,下面提供下载地址)
网盘链接:mha 软件下载
在管理节点安装 MHA 管理组件,先安装 node 再安装 manager 软件本身有依赖关系
yum install mha4mysql-node-0.56-0.el6.noarch.rpm
yum install mha4mysql-manager-0.56-0.el6.noarch.rpm
manager 需要一下包的依赖:
在 node 节点上,执行下面的命令:yum install perl-DBD-MySQL
*在 manager 节点上:
yum install perl-DBD-MySQL yum install perl-Config-Tiny yum install perl-Log-Dispatch yum install perl-Parallel-ForkManager yum install -y rrdtool perl-rrdtool rrdtool-devel perl-Params-Validate
坑点 1:发现 yum 不能安装 perl-Log-Dispatch 和 perl-Parallel-ForkManager:
下载并安装 EPEL
[root@localhost ~]# wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm [root@localhost ~]# rpm -ivh epel-release-latest-7.noarch.rpm [root@localhost ~]# yum repolist ##检查是否已添加至源列表
OK,检查好已添加至源后就可以进行 yum 安装了。
最后,将 mha4mysql-node 包复制到集群中的所有节点:
for i in 1 2 3 ; do scp mha4mysql-node-0.56-0.el6.noarch.rpm 10.211.55.2$i:/usr/src; done
mha_node: 安装到其他 node(所有其他机器)
[root@MHA_240 mha_soft]# yum install -y mha4mysql-node-0.54-0.el6.noarch.rpm
mha_manager: (MHA 20 上)
[root@MHA_240 mha]# cp -pr /usr/src/mha_soft/mha/ /etc/ //mha的配置文件和启动
文件(注意:这里我是没有找到 mha.cnf 和 mha_start,vi 创建 mha.cnf 文件)
配置如下:
[server default] #mysql admin account and password user=root password=62661206 #mha workdir and worklog manager_workdir=/etc/mha manager_log=/etc/mha/manager.log #mysql A/B account and pw repl_user=sky repl_password=62661206 #check_mha_node time ping_interval=1 #ssh account ssh_user=root [server1] hostname=10.211.55.20 ssh_port=22 master_binlog_dir=/var/lib/mysql candidate_master=1 [server2] hostname=10.211.55.21 ssh_port=22 master_binlog_dir=/var/lib/mysql candidate_master=1 [server3] hostname=10.211.55.22 ssh_port=22 master_binlog_dir=/var/lib/mysql candidate_master=1
检测 ssh 互信有没有问题
[root@localhost src]# masterha_check_ssh --conf=/etc/mha/mha.cnf
Tue Jun 13 02:21:31 2017 - [info] All SSH connection tests passed successfully. 有这个表示成功
测 AB
[root@localhost src]# masterha_check_repl --conf=/etc/mha/mha.cnf … MySQL Replication Health is OK.
坑点 2:masterha_check_repl 检测没有通过,报下面错误:
MHA 报错:There is no alive slave. We can't do failover
关于该问题,比较靠谱的解释是:(我的问题是没有关防火墙)
MHA 默认去连接 MySQL 的端口是:3306
如果你的主机名解析,或者你写的 IP 都没问题**,防火墙也关闭了**,那么,剩下的原因是:
你的 MySQL,没有运行在默认端口上。
如果不能修改 MySQL 的端口为:3306。
那么你可以给 MHA,添加 PORT 描述。
vi /etc/mha/mha_start //编辑 mha 启动脚本,直接运行下面启动也可以
nohup masterha_manager --conf=/etc/mha/mha.cnf > /tmp/mha_manager.log 2>&1 &
测试
现在两个 slave 的 Master_Host 同为 241,把 241 干掉后,就会选举新的 master 了!
先在 mha_manager 上打开日志:
tail -f /etc/mha/manager.log
到 20 上关闭 MySQL 服务:
service mysqld stop
查看 mha_manager 日志输出:
----- Failover Report ----- mha: MySQL Master failover 10.211.55.20 to 10.211.55.21 succeeded Master 10.211.55.21 is down! Check MHA Manager logs at localhost.localdomain:/etc/mha/manager.log for details. Started automated(non-interactive) failover. The latest slave 10.211.55.21(10.211.55.21:3306) has all relay logs for recovery. Selected 10.211.55.21 as a new master. 10.211.55.21: OK: Applying all logs succeeded. 10.211.55.21: This host has the latest relay log events. Generating relay diff files from the latest slave succeeded. 10.211.55.21: OK: Applying all logs succeeded. Slave started, replicating from 10.211.55.21. 10.211.55.21: Resetting slave info succeeded. Master failover to 10.211.55.20(10.211.55.21:3306) completed successfully.
看来 21 变成了 master!~
可以去新主上创建个库或到 21 上查看一下 master.info 来验证!!
下面演示 old_master 回来,如何保证 old_master 同步 new_master 的新产生的数据:
当 old_master 服务宕掉后,去 mha_monitor 上执行:
[root@mha_master mha]# grep -i change /etc/mha/manager.log (-i 是不区分大小写)
**Tue Jun 13 02:30:23 2018 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='10.211.55.21', MASTER_PORT=3306, MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POS=106, MASTER_USER='sky', MASTER_PASSWORD='xxx';**
然后在 old_master 上执行:
mysql> slave stop; mysql> change master to master_host='10.211.55.21', master_port=3306, master_log_file='binlog.000001', master_log_pos=106, master_user='sky', master_password='youpassword';(只需要修改密码即可) mysql> slave start;
坑点 3:mysql 的密码忘记了,重置密码的解决方案:
重置密码解决 MySQL for Linux 错误 ERROR 1045 (28000)
方法如下:
vim /etc/my.cnf(注:windows下修改的是my.ini)
在文档内搜索 mysqld 定位到[mysqld]文本段:
/mysqld(在 vim 编辑状态下直接输入该命令可搜索文本内容)
保存文档并退出:
:wq
2.接下来我们需要重启 MySQL:
service mysqld restart
3.重启之后输入#mysql 即可进入 mysql。
4.接下来就是用 sql 来修改 root 的密码
mysql> use mysql;
mysql> update user set password=password("你的新密码") where user="root";
mysql> flush privileges;
mysql> quit
到这里 root 账户就已经重置成新的密码了。
5.编辑 my.cnf,去掉刚才添加的内容,然后重启 MySQL。大功告成。
坑点 4:&>/dev/null 表示的意思
用 /dev/null 2>&1 这样的写法.这条命令的意思是将标准输出和错误输出全部重定向到/dev/null 中,也就是将产生的所有信息丢弃.
MHA failover(master 故障)后 VIP 漂移
MHA 架构中,master 来承担写请求,但是如果发生了 failover,那么就应该让 new_master 来承担写请求,有哪些方式可以实现呢?
- 改变 master 的 IP:在 web 上修改 PHP 页面的代码(所有写请求修改成 new_master 的 IP)
- 使用虚拟 IP(VIP),将 VIP 漂移给 new_master
显然,第二种方案要更加容易实现、高效。
实现起来,大家可能会首当其冲的想到 keepalived,但是在这里不适用,因为我们不好判断哪一个 salve 会在 failover 后变成 master(在 keepalived 中,VIP 根据物理路由器的优先级来确定,万一漂到一台 slave 上那可如何是好!)。不过我们可以通过脚本的方式来实现将 VIP 绑定到 new_master 上。
脚本思路如下:
脚本(/etc/mha/check_mysql)运行在 manager 上,它来管理 VIP
判断谁是主,确保它有 VIP,并继续判断,如果 slave 有 VIP,则收回。
脚本名称:master_vip_drift.sh(如果不是 salve 的话,|grep -w 'Slave_IO_Running'应该是错误的不是 1)
#!/bin/bash
VIP=10.211.55.23
NETMASK=255.255.255.0
MUSER=root
MPW=62661206
MYSQL_IP="10.211.55.20 10.211.55.21 10.211.55.22"
NIC=eth0
check_master(){
for IP in $MYSQL_IP
do
if ssh $IP "lsof -i :3306" &>/dev/null;then
ssh $IP "mysql -uroot -p62661206 -e 'show slave status \G'|grep -w 'Slave_IO_Running'" &>/dev/null
echo "$#"
if [ $? -eq 1 ];then
MY_master=$IP
echo "$MY_master"
fi
fi
done
}
check_master_alive(){
for IP in $MYSQL_IP
do
if ssh $IP "ip add show eth0"|grep inet|grep "$VIP" &>/dev/null;then
ssh $IP "lsof -i:3306" &>/dev/null
if [ $? -ne 0 ];then
ssh $IP "ifconfig $NIC:23 down "
fi
fi
done
}
VIP() {
for IP in $MYSQL_IP
do
ssh $IP "ip add show eth0"|grep inet|grep "$VIP" &>/dev/null
if [ $? -eq 0 ] && [[ $MY_master != "$IP" ]];then
ssh $IP "ifconfig $NIC:23 down"
elif [ $? -eq 1 ] && [[ $MY_master == "$IP" ]];then
ssh $IP "ifconfig $NIC:23 $VIP netmask $NETMASK up"
fi
done
}
while true
do
check_master
check_master_alive
VIP
sleep 1
done
坑点 5:shell 脚本报错:"[: =: unary operator expected"
shell 脚本报错:"[: =: unary operator expected"
究其原因,是因为如果变量 STATUS 值为空,那么就成了 [ = "OK"] ,显然 [ 和 "OK" 不相等并且缺少了 [ 符号,所以报了这样的错误。当然不总是出错,如果变量 STATUS 值不为空,程序就正常了,所以这样的错误还是很隐蔽的。
改成 if [[ $STATUS = "OK" ]];
分析 failover 日志—了解 MHA 工作流程
- tailf /etc/mha/manager.log
- 到 master 上关闭 MySQL 服务
- 查看日志并从头往下捋一遍
MySQL MHA 读写分离
Mysql_manager 和 HAProxy(10.211.55.23)
MySQL_A(10.211.55.20)
MySQL_B1(10.211.55.21)
MySQL_B2(10.211.55.22)
结构图说明:
a.MHA 对 abb 架构实行监控,发现 a 宕之后选出新 a(实现 VIP 漂移,仅 a 有 VIP)
b.haproxy 对 slave 集群实现负载均衡,承担读请求
c.web 集群请求后台数据,写请求传给 a(VIP),读请求传给 haproxy,haproxy 再对读请求实现分发达到负载均衡
安装 HAProxy(10.211.55.23)
网盘链接:mha 软件下载
yum install gcc -y tar xf haproxy-1.5.3.tar make TARGET=linux26 PREFIX=/usr/local/haproxy make install PREFIX=/usr/local/haproxy cp /usr/src/haproxy/haproxy-1.5.3/examples/haproxy.cfg /usr/local/haproxy/ cp /usr/src/haproxy/haproxy-1.5.3/examples/haproxy.init /etc/init.d/haproxy chmod 755 /etc/init.d/haproxy ln -s /usr/local/haproxy/sbin/* /usr/sbin/ mkdir /etc/haproxy mkdir /usr/share/haproxy ln -s /usr/local/haproxy/haproxy.cfg /etc/haproxy/ cd ..
设置配置文件
[root@HAProxy_247 haproxy]# cp haproxy.cfg /usr/local/haproxy/
编辑配置文件
[root@HAProxy_247 haproxy]# vim /usr/local/haproxy/haproxy.cfg
# this config needs haproxy-1.1.28 or haproxy-1.2.1 global log 127.0.0.1 local0 log 127.0.0.1 local1 notice #log loghost local0 info maxconn 4096 chroot /usr/share/haproxy uid 99 gid 99 daemon #debug #quiet defaults log global mode http #option httplog option dontlognull retries 3 option redispatch maxconn 2000 contimeout 5000 clitimeout 50000 srvtimeout 50000 listen MySQL 0.0.0.0:3306 mode tcp maxconn 200 balance roundrobin option mysql-check user root server mysql_1 10.211.55.21:3306 inter 1s rise 2 fall 2 server mysql_2 10.211.55.22:3306 inter 1s rise 2 fall 2 listen admin_status mode http bind 0.0.0.0:8899 option httplog log global stats enable stats refresh 10s stats hide-version stats realm Haproxy\ Statistics stats uri /admin-status stats auth admin:123456 stats admin if TRUE
启动 HAProxy 服务
[root@HAProxy_247 haproxy]# service haproxy start
访问 HAProxy 的网页(用户名密码查看配置文件舍子)
http://localhost:8899/admin-status
客户端测试:
mysql -uroot -pyoupassword -h 10.211.55.23
在 HAProxy 管理界面,可以看到那台 slave 响应的请求
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于