引入KeepAlived

一、概述

1、前言

前面我们构建了一个rabbitmq集群,其中有三个rabbitmq主机。之后用haproxy做了rabbitmq的的负载均衡,其中,haproxy有两个节点。但是到目前为止,我们只是单纯的构建了两个haproxy,并没有做haproxy的集群。这样只保证了rabbitmq有一个唯一入口,但没有保证haproxy有一个唯一入口,因为目前有两个haproxy节点,因此有两个haproxy入口。

haproxy官方推荐使用keepalived做haproxy集群的高可用。在每台haproxy主机上都安装keepalived,并将两台haproxy分别设置为主节点和备份节点,keepalived会生成一个虚拟ip,供给应用程序作为haproxy的唯一入口。

keepalived的虚拟ip漂移规则是:当前两台haproxy都安装了keepalived,并且是在一个虚拟路由组里(virtual_router_id相同),默认虚拟ip会漂移至优先级高的(priority高的),主机宕机后,主机priority降低,虚拟ip会漂移至虚拟路由组里优先级最高的,主机恢复,会重新加入到虚拟路由组里。

 

2、简介

Keepalived 是一个用于负载均衡和高可用的路由软件。其负载均衡(Load balancing)的特性依赖于 Linux 虚拟服务器(LVS)的 IPVS 内核模块,提供了 Layer 4 负载均衡器(TCP 层级,Layer 7 是 HTTP 层级,即计算机网络中的OSI 七层网络模型与 TCP/IP 四层网络模型)。

 

3、VRRP

Keepalived的实现基于VRRP(Virtual Router Redundancy Protocol,虚拟路由器冗余协议),VRRP是为了解决静态路由的高可用。

VRRP的基本架构图:

虚拟路由器由多个VRRP路由器组成,每个VRRP路由器都有各自的IP和共同的VRID(0-255),其中一个VRRP路由器通过竞选成为MASTER,占有VIP,对外提供路由
服务,其他成为BACKUP,MASTER以IP组播(组播地址:224.0.0.18)形式发送VRRP协议包,与BACKUP保持心跳连接,若MASTER不可用(或BACKUP接收不到
VRRP协议包),则BACKUP通过竞选产生新的MASTER并继续对外提供路由服务,从而实现高可用。

 

4、keepalived的功能

(1)依赖 IPVS 实现服务器的健康检查

如果服务器不可用,则keepalived将其从集群中移除,若服务器恢复可用,则keepalived将其重新加入集群中。

(2)通过实现 VRRPv2 协议来处理路由的故障切换

通过IP漂移,来实现服务的高可用。服务器集群共享一个虚拟IP,同一时间只有一个服务器占有虚拟IP并对外提供服务,若该服务器不可用,则虚拟IP漂移至另一
台服务器并对外提供服务

 

二、构建keepalived

1、前言

Docker快速构建HaProxy集群,并配置好rabbitmq的负载均衡 一文中,我们在构建haproxy集群时,在每个haproxy容器内都安装了keepalived,在本文中,会介绍keepalived和haproxy的搭配使用。

 

2、两台keepalived的配置
cd /data/docker-data/haproxy/keepalived/101
vi keepalived.conf 

global_defs {
   smtp_connect_timeout 3
   router_id haveyb_keepalived_101
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 105
    advert_int 1
    virtual_ipaddress {
        170.200.9.200
    }
}
cd /data/docker-data/haproxy/keepalived/102
vi keepalived.conf 

global_defs {
   smtp_connect_timeout 3
   router_id haveyb_keepalived_102
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    virtual_ipaddress {
        170.200.9.200
    }
}

可以发现,我们设置了一个漂移 IP (VIP, virtual ip): 170.200.9.200,该值应该设置为和haproxy容器的ip在一个网段内,haproxy容器的ip是170.200.9.101、170.200.9.102,那我们就可以设置漂移 IP为170.200.9.200

这里有三个参数需要注意:

(1)router_id

它表示keepalived在集群中的名称,集群中每个keealived的router_id应该设置为不一样的

(2)virtual_router_id

它表示虚拟路由id,一个keepalived集群中的每个节点的virtual_router_id都应该相同。取值范围 0-255,用于区分组播。

(3)interface

该值表示vrrp实例绑定的网络接口,用于发送VRRP包,该值应该根据ifconfig命令的结果来填写,keepalived安装在了哪里,就在哪里执行ifconfig,然后填写该值。比如这里我们把keepalived安装在了容器内,就应该在容器内执行ifconfig,然后根据结果填写该值。

 

3、启动keepalived
# 进入容器
docker exec -it haproxy_101 bash
# 启动keepalived
keepalived -f /keepalived/keepalived.conf
# 退出容器,返回宿主机
exit
# 进入容器
docker exec -it haproxy_102 bash
# 启动keepalived
keepalived -f /keepalived/keepalived.conf
# 退出容器,返回宿主机
exit

 

4、测试keepalived能否正常运行

keepalived能否正常运行的标志是两台主机上是否有一台存在漂移IP。漂移IP默认在master上,如果master挂掉了,会漂移到backup上。

(1)进入haproxy_101容器,执行 ip addr 命令,查看是否有漂移ip 170.200.9.200。

docker exec -it haproxy_101 bash
ip addr

可以看到,漂移ip在harpoxy_101容器上。

(2)进入haproxy_102容器,执行 ip addr 命令,查看是否有漂移ip 170.200.9.200

docker exec -it haproxy_102 bash
ip addr

可以看到,haproxy_102容器内,并没有漂移ip170.200.9.200

(3)将haproxy_101容器停掉,然后到haproxy_102容器上查看,漂移IP是否已经漂移过来了

docker stop haproxy_101
docker exec -it haproxy_102 bash
ip addr

我们发现,漂移IP已经漂移到haproxy_102容器上了。

 

5、使用Nginx对外提供服务

因为我们给两台haproxy挂载的虚拟IP是内网的,是无法直接用该虚拟IP对外提供访问的,因此需要用nginx做请求转发。但有一点需要注意的是,我们的nginx也是容器,在容器内部如果想要访问到另一个容器内的网络,则必须保证两个容器在一个网段内。

因为我们两台haproxy和keepalived的虚拟IP都在170.200.9.网段内,因此我们这里指定接下来创建的nginx容器网络IP为170.200.9.10

(1)拉取nginx镜像
docker pull haveyb/nginx
docker tag docker.io/haveyb/nginx nginx1.21
docker rmi docker.io/haveyb/nginx
(2)查看haproxy在使用的网络名称
# 查看网络列表(在宿主机执行)
docker network ls

可以看出,haproxy_101和haproxy_102使用的网络名称是haproxy_haproxy。

说明:虽然我们在docker-compose.yml中定义的网络名称是haproxy,但是docker会对这个做一点改动,但不难分析出来,而且可以使用docker inspect 容器名称 去查看一个容器的详细情况,其中也包括使用的网络名称。

(3)创建nginx容器
docker run -itd --name nginx --network=haproxy_haproxy --ip=170.200.9.10 -p 5600:5600 nginx1.21
(3)编辑nginx配置文件
# 进入nginx容器
docker exec -it nginx bash
# 进入nginx配置文件所在目录
cd /etc/nginx
# 编辑nginx.conf
vi nginx.conf

worker_processes 1;
error_log logs/error.log warn;

events {
    worker_connections 1024;
}

stream{
    server {
        listen 5600;
        proxy_pass 170.200.9.200:5600;
    }
}

重点注意:stream块和http是平级的,放错位置会报错

(4)重启nginx,以加载修改后的配置
# 退出容器,回到宿主机
exit
# 重启容器,以加载修改后的配置
docker restart nginx

 

6、使用PHP程序访问,验证结果
 public function actionTest()
 {
        $con = new AMQPStreamConnection('192.168.78.200', 5600, 'root', '123456');
        var_dump($con);
        $re = $con->channel();
        var_dump($re);
 }

返回了一些rabbitmq连接信息,说明连接成功了

 

7、整体流转流程

(1)PHP程序访问Nginx的5600端口号

(2)Nginx接收来自5600端口号的请求,并将请求转发到虚拟IP

(3)keepalived安装在两台haproxy容器里,所以虚拟ip是在两台haproxy容器里漂移

(4)假设虚拟IP漂移到了haproxy_101容器里的keepalived,那么Nginx转发5600端口号的请求到虚拟IP,就相当于转发5600端口号的请求到haproxy_101容器的IP地址

docker exec -it haproxy_101 bash
ip addr

此时,虚拟ip漂移到了haproxy_101,请求170.200.9.200:5600相当于直接请求170.200.9.101:5600;同理,如果虚拟IP漂移到了haproxy_102,那么请求170.200.9.200:5600则相当于直接请求170.200.9.102:5600

(5)因为两台haproxy都对rabbitmq做了同样的负载均衡,并且负载均衡监控的是5600端口号,所以harpoxy最终会把请求分发给三台rabbitmq中的一台

 

8、总结

到这里,就完成了keepalived+haproxy+rabbitmq的rabbitmq负载均衡集群架构。

但相对而言,还有一些不足,比如当前两台haproxy部署在了一台服务器,rabbitmq也部署在了一台服务器上,这在生产环境肯定是不行的。

如何解决当rabbitmq、haproxy、nginx部署在不同服务器上时,网络通信的问题呢?

这时我们就可以使用docker swarm集群技术,将多台服务器通过docker swarm加入到一个集群中,那时,即使所有的容器都部署在不同服务器上,只要所有服务器都通过docker swarm加入了同一个swarm集群,那就和单机部署并没有太大区别了。

关于将多台服务器加入同一个swarn集群的方法也很简单,可以查看文章 docker-搭建swarm集群