mysql 高可用架构之 MHA,haproxy 实现读写分离详解(自己安装实践)

本贴最后更新于 1956 天前,其中的信息可能已经时移世易

参考地址: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:

解决方案:CentOS7 安装第三方 yum 源 EPEL

下载并安装 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 表示的意思

用 /dev/null 2>&1 这样的写法.这条命令的意思是将标准输出和错误输出全部重定向到/dev/null 中,也就是将产生的所有信息丢弃.


MHA failover(master 故障)后 VIP 漂移

MHA 架构中,master 来承担写请求,但是如果发生了 failover,那么就应该让 new_master 来承担写请求,有哪些方式可以实现呢?

  1. 改变 master 的 IP:在 web 上修改 PHP 页面的代码(所有写请求修改成 new_master 的 IP)
  2. 使用虚拟 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 脚本报错

shell 脚本报错:"[: =: unary operator expected"

究其原因,是因为如果变量 STATUS 值为空,那么就成了 [ = "OK"] ,显然 [ 和 "OK" 不相等并且缺少了 [ 符号,所以报了这样的错误。当然不总是出错,如果变量 STATUS 值不为空,程序就正常了,所以这样的错误还是很隐蔽的。

改成 if [[ $STATUS = "OK" ]];

分析 failover 日志—了解 MHA 工作流程
  1. tailf /etc/mha/manager.log
  2. 到 master 上关闭 MySQL 服务
  3. 查看日志并从头往下捋一遍

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)

image1.png

结构图说明:

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 响应的请求

image2.png

  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    675 引用 • 535 回帖
  • MHA
    1 引用
  • 代理
    46 引用 • 103 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...