在初步了解了 keepalived 的作用后,手痒难耐,于是动手实践部署了一个 Nginx + keepalived + Tomcat 组合的双主高可用负载均衡集群。
实现 VIP 漂移
在搭建集群之前,先简单使用 keepalived 实现 VIP 漂移。准备两台服务器(10.5.96.3 和 10.5.96.4),两台机器都要安装 keepalived。
1 2 3 4 5 6 7 8 9 10 11 12 13
   |  yum install -y openssl openssl-devel gcc gcc-c++
 
  wget https://www.keepalived.org/software/keepalived-2.0.18.tar.gz && tar xf keepalived-2.0.18.tar.gz
 
  mkdir /usr/local/keepalived && cd keepalived-2.0.18 && ./configure prefix=/usr/local/keepalived/ make && make install
 
  mkdir /etc/keepalived && cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/keepalived
 
  | 
 
接下来需要修改 keepalived 的配置文件,我选择将 10.5.96.3 作为主,10.5.96.4 作为备,虚拟 IP 地址设置成 10.5.96.7。主的配置为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | ! Configuration File for keepalived
  # 实例配置 vrrp_instance VI_1 {     # 指定为 master 主机     state MASTER     # VIP 绑定的网卡设备,用来发送 VRRP 包做心跳检测     interface eth1     # 虚拟路由 id,是一个唯一值,取值 0 到 255 之间     # 相同的组(主备)之间配置须一致,不同的组需要设置不同的值     virtual_router_id 51     # 优先级,在选举 master 时会使用该值,如果要成为 master,这个选项的值最好高于其他机器 50 个点     priority 100     # 健康检查时间间隔,即每隔 1 秒发起一次 VRRP 组播     advert_int 1     # 虚拟 IP 地址     virtual_ipaddress {         10.5.96.7     } }
   | 
 
备的配置为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | ! Configuration File for keepalived
  # 实例配置 vrrp_instance VI_1 {     # 指定为 backup 主机     state BACKUP     # VIP 绑定的网卡设备,用来发送 VRRP 包做心跳检测     interface eth1     # 虚拟路由 id,是一个唯一值,取值 0 到 255 之间     # 相同的组(主备)之间配置须一致,不同的组需要设置不同的值     virtual_router_id 51     # 优先级,在选举 master 时会使用该值,如果要成为 master,这个选项的值最好高于其他机器 50 个点     priority 50     # 健康检查时间间隔,即每隔 1 秒发起一次 VRRP 组播     advert_int 1     # 虚拟 IP 地址     virtual_ipaddress {         10.5.96.7     } }
   | 
 
接下来启动两台机器分别使用命令 systemctl start keepalived 启动 keepalived,然后使用 ip ad 命令观察网络配置情况。
Master 的网络配置:

Backup 的网络配置:

接下来停掉 Master 的 keepalived,再观察 Backup 的网络配置,会发现 VIP 漂移到了该机器上。然后重新启动 Master 的 keepalived,再次观察,会发现 VIP 又重新漂移到了主机器上。
可能会遇到的问题
主备同时获取到了 VIP 地址,也就是脑裂现象。keepalived 默认需要使用 D 类多播地址 224.0.0.18 进行心跳通信,因此需要修改防火墙的规则:
1 2 3 4 5 6 7
   |  firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface eth0 --destination 224.0.0.18 --protocol vrrp -j ACCEPT firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --out-interface eth0 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
  firewall-cmd --reload
  systemctl restart keepalived
 
  | 
 
实现双主高可用负载均衡集群
双机高可用一般分为两种。一种是主从模式,即一台机器为主,另一台机器为从。正常情况下,主服务器绑定一个公网虚拟 IP,作为流量入口提供负载均衡服务,而热备服务器则处于空闲状态。当主服务器发生故障时,VIP 发生漂移,热备服务器接管主服务器的公网虚拟 IP,继续提供负载均衡服务。这种方式永远会有一台服务器处于空间状态,浪费资源。另一种就是双主模式,即两台服务器互为主备,同时处于活动状态,各自绑定一个公网虚拟 IP。当其中一台发生故障时,另一台接管发生故障的服务器的公网虚拟 IP,承担所有的请求。
公网虚拟 IP 其实就是公网 IP,只不过我们将它用作 VIP。很多云服务厂商提供的弹性公网 IP 服务就可以满足我们的需求。双主是两个 Ningx 同时提供服务,因此系统对外会有两个 IP 地址,此时配合 DNS 轮询可以将一个域名的流量打到两台 Nginx 服务机器上。
接下来一共需要四台服务器,其中两台(10.5.96.3 和 10.5.96.4)使用 Nginx 做负载均衡,另外两台(10.5.96.5 和 10.5.96.6)作为真实节点服务器,运行 Tomcat 容器,两个 VIP 分别设置为 10.5.96.7 和 10.5.96.8。首先在两台真实节点服务器上安装 JDK 和 Tomcat,安装完毕后简单编写一个测试的 jsp 页面。然后在两台负载均衡服务器上安装 Nginx 并添加配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | #gzip  on; upstream tomcat {     server 10.5.96.5:8080 weight=1 max_fails=1 fail_timeout=10s;     server 10.5.96.6:8080 weight=1 max_fails=1 fail_timeout=10s; }
  server {     listen       80;     server_name  localhost;     location / {         root   html;         index  index.html index.htm;         proxy_pass http://tomcat;     } }
   | 
 
接下来需要在两台负载均衡机器上分别安装 keepalived,用于实现故障切换,10.5.96.3 的配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
   | ! Configuration File for keepalived
  vrrp_script check_nginx {     script "/root/nginx.sh"     interval 2     weight 10 }
  vrrp_instance VI_1 {     state MASTER     interface eth1     virtual_router_id 51     priority 100     advert_int 1     authentication {         auth_type PASS         auth_pass 1111     }
      track_script {         check_nginx     }
      virtual_ipaddress {         10.5.96.7     } }
  vrrp_instance VI_2 {     state BACKUP     interface eth1     virtual_router_id 52     priority 90     advert_int 1     authentication {         auth_type PASS         auth_pass 1111     }
      track_script {         check_nginx     }
      virtual_ipaddress {         10.5.96.8     } }
   | 
 
10.5.96.4 的配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
   | ! Configuration File for keepalived
  vrrp_script check_nginx {     script "/root/nginx.sh"     interval 2     weight 10 }
  vrrp_instance VI_1 {     state BACKUP     interface eth1     virtual_router_id 51     priority 90     advert_int 1     authentication {         auth_type PASS         auth_pass 1111     }
      track_script {         check_nginx     }
      virtual_ipaddress {         10.5.96.7     } }
  vrrp_instance VI_2 {     state MASTER     interface eth1     virtual_router_id 52     priority 100     advert_int 1     authentication {         auth_type PASS         auth_pass 1111     }
      track_script {         check_nginx     }
      virtual_ipaddress {         10.5.96.8     } }
   | 
 
其中 nginx.sh 是 Nginx 进程状态检测脚本。设置该脚本后,keepalived 会定期执行该脚本,在 Nginx 服务没有启动或者出现问题关闭时重新启动 Nginx 服务,在重启失败后会关闭该机器上的 keepalived 服务,从而导致 VIP 漂移,实现故障切换。
keepalived 会根据脚本执行的结果动态调整 vrrp_instance 的优先级(可能是降低或者提高),从而引发新一轮的 Master 选举。
1 2 3 4 5 6 7 8 9 10 11 12
   | #!/bin/bash
  jc=`ps -C nginx --no-header|wc -l` if [ $jc -eq 0 ];then     /usr/local/nginx/sbin/nginx     sleep 2          jc2=`ps -C nginx -no-header|wc -l`     if [ $jc2 -eq 0 ];then         systemctl stop keepalived     fi fi
   | 
 
一切准备就绪后,分别启动两台机器上的 Nginx 服务和 keepalived 服务。查看网络配置情况,其中 10.5.96.3 的配置如下:

10.5.96.4 的配置如下:

当某一台机器发生故障时,VIP 漂移,另一个机器就会同时接管这两个 VIP,当机器故障恢复后,VIP 又会漂移回去,恢复到一开始的配置。