Heartbeat + haproxy + MySQL 双主复制实现读写负载均衡及高可用

目录

一、中间件简述

1. Heartbeat 简介

2. haproxy 简介

二、安装配置

1. 基本环境

2. 配置 MySQL 双主复制

3. 安装配置 haproxy

4. 安装配置 Heartbeat

5. 创建 MySQL 服务检测脚本

三、功能测试

1. 验证 haproxy 的负载均衡轮询策略

2. 验证 MySQL 的高可用性

3. 验证宕机重新上线后自动添加到 haproxy 中

4. 验证 haproxy 的高可用性

四、总结

参考:


        上一篇我们使用 Heartbeat 的 HA 功能,实现 MySQL 主从复制的自动故障切换。它的工作原理是:当 Heartbeat 启动时,会将 VIP 绑定到 haresources 文件中指定的主机上。自定义 mysql_check 检查脚本,定期(例子中为三秒钟)检查本机 MySQL 的服务器状态,如果 MySQL 不可用,则停止本机的 Heartbeat 服务。Heartbeat 每秒钟(由 keepalive 参数指定)会检查一次本机心跳,如果不存在,则将 VIP 绑定到另一台机器上,同时调用 remove_slave 脚本执行从库切换为主库的操作。

        本篇我们将做另一个实验,利用 haproxy 实现 MySQL 双主复制的读写负载均衡与 MySQL 的高可用,同时用 Heartbeat 保证两台负载均衡器的高可用性。

一、中间件简述

1. Heartbeat 简介

        参见“https://blog.youkuaiyun.com/wzy0623/article/details/81188814#一、Heartbeat简介”。

2. haproxy 简介

        haproxy 是一个开源的高性能的反向代理或者说是负载均衡服务软件,它支持双机热备、虚拟主机、基于 TCP 和 HTTP 应用代理等功能。其配置简单,而且拥有很好的对服务器节点的健康检查功能(相当于 keepalived 健康检查),当其代理的后端服务器出现故障时,haproxy 会自动将该故障服务器摘除,当服务器的故障恢复后 haproxy 还会自动重新添加回服务器主机。

        haproxy 实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存、系统调度器以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户空间(User-Space)实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差,这就是为什么必须对其进行优化以使每个 CPU 时间片(Cycle)做更多的工作。

        haproxy 特别适用于那些负载特大的 web 站点,这些站点通常又需要会话保持或七层处理。haproxy 运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全地整合进当前架构中,同时可以保护 web 服务器不被暴露到网络上。

        haproxy 软件引入了 frontend、backend 的功能,frontend(acl 规则匹配)可以根据任意 HTTP 请求头做规则匹配,然后把请求定向到相关的 backend(server pools,等待前端把请求转过来的服务器组)。通过 frontend 和 backend,我们可以很容易的实现 haproxy 的七层代理功能。

二、安装配置

1. 基本环境

        OS:CentOS Linux release 7.2.1511 (Core)
        172.16.1.126:Heartbeat + haproxy + MySQL Replication Master 
        172.16.1.127:Heartbeat + haproxy + MySQL Replication Master
        172.16.1.100:VIP

        整体架构图如图1 所示。

图1

2. 配置 MySQL 双主复制

        所谓 MySQL 双主复制,就是两个 MySQL 服务器都能读能写,数据记录通过二进制传达给对方从而保持数据的一致性。就本例简而言之,172.16.1.126 到 172.16.1.127 的主从复制 + 172.16.1.127 到 172.16.1.126 的主从复制 = 172.16.1.126、172.16.1.127的双主复制。双主复制的详细配置步骤可以参考这篇文章:MySQL主从复制与主主复制 - 那一叶随风 - 博客园,这里从略。

        与主从复制相比,双主复制需要注意以下三个参数的设置:

  • log_slave_updates:要设置为 true,将复制事件写入本机 binlog。一台服务器既做主库又做从库时此选项必须要开启。
  • auto_increment_offset 和 auto_increment_increment:为避免自增列冲突,需要设置这两个参数,例如在双主复制中,可以配置如下:
    # masterA自增长ID
    auto_increment_offset = 1
    auto_increment_increment = 2   #奇数ID
    # masterB自增加ID
    auto_increment_offset = 2
    auto_increment_increment = 2   #偶数ID

3. 安装配置 haproxy

        以下步骤用 root 用户在 172.16.1.126、172.16.1.127 两个主机上执行。

(1)从以下地址下载 haproxy 源码
https://www.haproxy.org/download/1.8/src/haproxy-1.8.12.tar.gz

(2)创建 haproxy 运行账户和组

groupadd haproxy #添加haproxy组
useradd -g haproxy haproxy -s /bin/false #创建账户haproxy并加入到haproxy组

(3)解压

tar zxvf haproxy-1.8.12.tar.gz
cd haproxy-1.8.12

(4)查看操作系统版本信息

[root@hdp3~/haproxy-1.8.12]#uname -r
3.10.0-327.el7.x86_64
[root@hdp3~/haproxy-1.8.12]#

(5)编译与安装

make TARGET=linux3100 CPU=x86_64 PREFIX=/usr/local/haprpxy
make install PREFIX=/usr/local/haproxy

        参数说明:

  • TARGET:使用 uname -r 查看内核,如:2.6.18-371.el5,此时该参数就为 linux26。kernel 等于 2.6.28 的用:TARGET=linux2628,等等。
  • CPU:使用 uname -r 查看系统信息,如 x86_64 GNU/Linux,此时该参数就为 x86_64。
  • PREFIX:指定 haprpxy 安装路径。

(6)设置 haproxy

mkdir -p /usr/local/haproxy/conf #创建配置文件目录
mkdir -p /etc/haproxy #创建配置文件目录
touch /usr/local/haproxy/conf/haproxy.cfg #创建配置文件
ln -s /usr/local/haproxy/conf/haproxy.cfg /etc/haproxy/haproxy.cfg #添加配置文件软连接
cp -r /root/haproxy-1.8.12/examples/errorfiles /usr/local/haproxy/errorfiles #拷贝错误页面
ln -s /usr/local/haproxy/errorfiles /etc/haproxy/errorfiles #添加软连接
mkdir -p /usr/local/haproxy/log #创建日志文件目录
touch /usr/local/haproxy/log/haproxy.log #创建日志文件
ln -s /usr/local/haproxy/log/haproxy.log /var/log/haproxy.log #添加软连接
cp /root/haproxy-1.8.12/examples/haproxy.init /etc/rc.d/init.d/haproxy #拷贝开机启动文件
chmod +x /etc/rc.d/init.d/haproxy #添加脚本执行权限
chkconfig haproxy on #设置开机启动
ln -s /usr/local/haproxy/sbin/haproxy /usr/sbin #添加软连接

(7)配置 haproxy 参数

        编辑 /usr/local/haproxy/conf/haproxy.cfg,内容如下: 

global
    log         127.0.0.1 local2           # 日志定义级别(err | warning | info | debug)
    chroot      /usr/local/haproxy         # 当前工作目录
    pidfile     /var/run/haproxy.pid       # 进程id
    maxconn     4000                       # 最大连接数
    user        haproxy                    # 运行改程序的用户
    group       haproxy
    daemon                                 # 后台形式运行
    stats socket /usr/local/haproxy/stats

defaults
    mode                    tcp            # haproxy运行模式(http | tcp | health)
    log                     global         # 采用全局定义的日志
    option                  dontlognull    # 不记录健康检查的日志信息
    option                  redispatch     # serverId对应的服务器挂掉后,强制定向到其它健康的服务器
    retries                 3              # 三次连接失败则服务器不用
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s            # 连接超时
    timeout client          1m             # 客户端超时
    timeout server          1m             # 服务器超时
    timeout http-keep-alive 10s
    timeout check           10s            # 心跳检测
    maxconn                 600            # 最大连接数

listen stats                               # 配置haproxy状态页(用来查看的页面)
    mode http
    bind :8888
    stats enable
    stats hide-version                     # 隐藏haproxy版本号
    stats uri     /haproxyadmin?stats      # 一会用于打开状态页的uri
    stats realm   Haproxy\ Statistics      # 输入账户密码时的提示文字
    stats auth    admin:admin              # 用户名:密码

frontend  main 
    bind 0.0.0.0:6603
    # 使用6603端口。监听前端端口(表示任何ip访问6603端口都会将数据轮番转发到mysql服务器群组中)
    default_backend             mysql      # 后端服务器组名

backend mysql
    balance     roundrobin                 # 使用轮询方式调度
    server mysql1 172.16.1.126:3306 check port 3306 maxconn 300
    server mysql2 172.16.1.127:3306 check port 3306 maxconn 300

(8)启动日志

        编辑 /etc/rsyslog.conf 文件,去掉以下两行的注释,并在其后添加一行:

# Provides TCP syslog reception
$ModLoad imtcp                   # 去掉注释
$InputTCPServerRun 514           # 去掉注释
local2.*   /var/log/haproxy.log  # 添加此行

(9)启动 haproxy

systemctl start haproxy
systemctl status haproxy -l
systemctl stop haproxy
systemctl restart haproxy

        此时打开浏览器输入 172.16.1.126:8888/haproxyadmin?stats,用 admin/admin 登陆后如图2 所示,表明安装 haproxy 成功。

图2

4. 安装配置 Heartbeat

        Heartbeat 的源码编译安装需要依次安装 Cluster Glue、Resource Agents 和 Heartbeat 三个软件,并且三个软件要安装在相同目录下。详细安装配置步骤参考:https://blog.youkuaiyun.com/wzy0623/article/details/81188814#二、安装Heartbeat

        这里需要注意的是 haresources 的设置。在上一篇中,我们建立了一个名为 mysql 的脚本,它调用 remove_slave.sh。当 Heartbeat 主机获得资源时,将自动把 MySQL 主从复制中的 slave 置为 master。这次我们用 /usr/local/heartbeat/etc/ha.d/haresources 来启动 haproxy,文件内容只有如下一行:

hdp3 172.16.1.100 haproxy

        而 /usr/local/heartbeat/etc/ha.d/resource.d/haproxy 文件中也只有如下一行:

/etc/init.d/haproxy restart

        资源只有 VIP,我们用这种配置保证 haproxy 的高可用性。当初始启动 Heartbeat 后,VIP 绑定在 172.16.1.126 上。

5. 创建 MySQL 服务检测脚本

        与上一篇的实验类似,这里保留自定义 mysql_check 脚本用于检查本机 MySQL 的服务器状态。脚本内容与部署参见https://blog.youkuaiyun.com/wzy0623/article/details/81188814#4.%20创建MySQL服务检测脚本

三、功能测试

1. 验证 haproxy 的负载均衡轮询策略

        用客户端连接 VIP,并多次执行 MySQL 查询,可以看到查询请求依次被发送到在两个主机上执行。

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>

2. 验证 MySQL 的高可用性

        在 172.16.1.126 上杀掉 MySQL:

pkill -9 mysqld

        用客户端连接 VIP,并多次执行 MySQL 查询,可以看到查询请求都被发送到 172.16.1.127。一台 MySQL 宕机不影响应用的正常使用,保证了 MySQL 服务的高可用性。

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>

3. 验证宕机重新上线后自动添加到 haproxy 中

        在 172.16.1.126 再次启动 MySQL,并重启 haproxy 服务:

service mysql start
systemctl restart haproxy

        用客户端连接 VIP,并多次执行 MySQL 查询,可以看到查询请求依次被发送到在两个主机上执行。

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>

4. 验证 haproxy 的高可用性

        初始 VIP 在 126,126 的 haproxy 启动,127 的 haproxy 停止。客户端访问:

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>

        停止 172.16.1.126 上的 MySQL 服务:

pkill -9 mysqld

        mysql_check 会检测到本机 MySQL 服务宕机,触发停止 heartbeat 服务。VIP 漂移到 172.16.1.127,同时 172.16.1.127 上的 haproxy 被拉起:

[root@hdp4~]#ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    link/ether 00:50:56:a5:49:7f brd ff:ff:ff:ff:ff:ff
    inet 172.16.1.127/24 brd 172.16.1.255 scope global ens160
       valid_lft forever preferred_lft forever
    inet 172.16.1.100/24 brd 172.16.1.255 scope global secondary ens160:0
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fea5:497f/64 scope link 
       valid_lft forever preferred_lft forever
[root@hdp4~]#
[root@hdp4~]#
[root@hdp4~]#/etc/init.d/haproxy status
● haproxy.service - SYSV: HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited for high availability environments.
   Loaded: loaded (/etc/rc.d/init.d/haproxy)
   Active: active (running) since Thu 2018-07-26 11:25:47 CST; 26s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 532199 ExecStop=/etc/rc.d/init.d/haproxy stop (code=exited, status=0/SUCCESS)
  Process: 532205 ExecStart=/etc/rc.d/init.d/haproxy start (code=exited, status=0/SUCCESS)
 Main PID: 532210 (haproxy)
   CGroup: /system.slice/haproxy.service
           └─532210 /usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid

Jul 26 11:25:47 hdp4 systemd[1]: Starting SYSV: HA-Proxy is a TCP/HTTP reverse proxy which is particularly suite...ts....
Jul 26 11:25:47 hdp4 haproxy[532205]: Starting haproxy: [  OK  ]
Jul 26 11:25:47 hdp4 systemd[1]: Started SYSV: HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited...ents..
Hint: Some lines were ellipsized, use -l to show in full.
[root@hdp4~]#

        客户端访问不受影响:

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 126   |
+---------------+-------+

C:\WINDOWS\system32>mysql -utest -p123456 -P6603 -h172.16.1.100 -e "show variables like 'server_id'"\
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 127   |
+---------------+-------+

C:\WINDOWS\system32>

        在 172.16.1.126 上再次启动 heartbeat,VIP 并不发生漂移,仍然停留在 172.16.1.127 上。

[root@hdp3~]#systemctl start heartbeat
[root@hdp3~]#
[root@hdp3~]#
[root@hdp3~]#ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:50:56:a5:0f:77 brd ff:ff:ff:ff:ff:ff
    inet 172.16.1.126/24 brd 172.16.1.255 scope global ens32
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fea5:f77/64 scope link 
       valid_lft forever preferred_lft forever
[root@hdp3~]#

四、总结

  1. 之所以要使用 MySQL 双主复制而不是主从复制,是因为本方案中并没有涉及读写分离,而是在两个等价的 MySQL 服务器之间做读写负载均衡。
  2. Heartbeat 实现了 haproxy 的 HA,避免了 haproxy 的单点故障,出现故障时可以自动切换到正常的节点。
  3. haproxy 服务器提供了负载均衡的作用,将用户请求分发到多个 backend。同时,一台 MySQL 故障并不会影响整个集群,因为 haproxy 会检测 backend 的状态,并据此自动添加或删除集群中的 MySQL 服务。
  4. 如本例的配置,需要考虑单台 MySQL 服务器的负载最好不要超过 50%,否则一旦某台 MySQL 服务器故障,可能出现另一台正常 MySQL 不堪重负的情况。
  5. 只采用本例的配置无法处理“脑裂”问题。例如,当心跳线闪断,slave 获得 VIP,而此时 master 除了与 slave 失去联系,本身并无任何问题,也绑定同一 VIP。当心跳恢复正常时,就会出现 VIP 的冲突等问题。脑裂是一个比较复杂的话题,通常需要引入其它插件,并且“多管齐下”才能彻底解决。

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值