Keepalived是一个基于VRRP协议来实现的服务高可用方案,可以利用其来避免IP单点故障,与其它负载均衡技术(如lvs、haproxy、nginx)一起工作。

VRRP协议

  VRRP全称 Virtual Router Redundancy Protocol,即 虚拟路由冗余协议。可以认为它是实现路由器高可用的容错协议,即将N台提供相同功能的路由器组成一个路由器组(Router Group)这个组里面有一个master和多个backup,但在外界看来就像一台一样,构成虚拟路由器,拥有一个虚拟IP(vip,也就是路由器所在局域网内其他机器的默认路由)占有这个IP的master实际负责ARP相应和转发IP数据包,组中的其它路由器作为备份的角色处于待命状态。master会发组播消息,当backup在超时时间内收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master,保证路由器的高可用。

  在VRRP协议实现里,虚拟路由器使用 00-00-5E-00-01-XX 作为虚拟MAC地址,XX就是唯一的 VRID (Virtual Router IDentifier),这个地址同一时间只有一个物理路由器占用。在虚拟路由器里面的物理路由器组里面通过多播IP地址 224.0.0.18 来定时发送通告消息。每个Router都有一个 1-255 之间的优先级别,级别最高的(highest priority)将成为主控(master)路由器。通过降低master的优先权可以让处于backup状态的路由器抢占(pro-empt)主路由器的状态,两个backup优先级相同的IP地址较大者为master,接管虚拟IP。

VRRP的工作过程是这样的:

  1. 虚拟路由器中的路由器根据优先级选举出Master,Master路由器通过发送免费ARP报文,将自己的虚拟MAC地址通告给与它连接的设备。
  2. Master路由器周期性发送VRRP报文,以公布自己的配置信息(优先级等)和工作状态
  3. 如果Master故障,虚拟路由器中的Backup路由器将根据优先级重新选举新的Master
  4. 虚拟路由器状态切换时,Master路由器由一台设备切换会另外一台设备,新的Master路由器只是简单的发送一个携带虚拟MAC地址和虚拟IP的免费ARP报文,这样就可以更新其他设备中缓存的ARP信息
  5. Backup路由器的优先级高于Master时,由Backup的工作方式(抢占式或者非抢占式)决定是否重新选举Master。

Keepalived

Keepalived的作用是检测服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作;当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。

健康检查和失败切换是keepalived的两大核心功能。

所谓的健康检查, 就是采用tcp三次握手, icmp请求, http请求, udp echo请求等方式对负载均衡器后面的实际的服务器(通常是承载真实业务的服务器)进行保活;

而失败切换主要是应用于配置了主备模式的负载均衡器, 利用VRRP(虚拟路由冗余协议, 可参考RFC文档http://tools.ietf.org/html/rfc5798) 维持主备负载均衡器的心跳, 当主负载均衡器出现问题时, 由备负载均衡器承载对应的业务, 从而在最大限度上减少流量损失, 并提供服务的稳定性。

keepalived启动后以后会有一个主进程Master,它会生成还有2个子进程,一个是VRRP Stack负责VRRP(也就是VRRP协议的实现)、一个是Checkers负责IPVS的后端的应用服务器的健康检查,当检测失败就会调用IPVS规则删除后端服务器的IP地址,检测成功了再加回来。当检测后端有失败的情况可以使用SMTP通知管理员。另外VRRP如果检测到另外一个Keepalive失败也可以通过SMTP通知管理员。

Control Plane:这个就是主进程,主进程的功能是分析配置文件,读取、配置和生效配置文件,指挥那2个子进程工作。

WatchDog:看门狗,这个是Linux系统内核的一个模块,它的作用是帮助主进程盯着那2个子进程,因为主进程并不负责具体工作,具体工作都是子进程完成的。如果子进程挂了,那Keepalived就不完整了,所以那2个子进程会定期的向主进程打开的一个内部Unix Socket文件写心跳信息。如果有某个子进程不写信息了,它就会重启子进程,主进程就是让WatchDog来监控子进程的。

使用Keepalived+nginx 实现高可用主备方案

预备

负载服务器master及nginx ,IP:192.168.65.100

负载服务器backup及nginx,IP:192.168.65.101

负载服务器虚拟ip:192.168.65.99

#安装keepalived 
yum install -y keepalived

确认服务器用的网卡,我这边是ens33

编写配置文件 /etc/keepalived/keepalived.conf

MASTER

! Configuration File for keepalived
 全局配置
 global_defs {
 #邮件通知信息
 notification_email {
      acassen@firewall.loc
      failover@firewall.loc
      sysadmin@firewall.loc
    }
 #定义发件人
 notification_email_from Alexandre.Cassen@firewall.loc
 #smtp服务器地址
 smtp_server 192.168.200.1
    smtp_connect_timeout 30
 #路由标识
 router_id LVS_DEVEL
 vrrp_skip_check_adv_addr
   # vrrp_strict 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
    vrrp_garp_interval 0
    vrrp_gna_interval 0
 }
vrrp_script check_nginx {     #定义脚本
    script "“/etc/keepalived/check_nginx.sh"  --- 表示将一个脚本信息赋值给变量check_nginx
    interval 3    --- 执行监控脚本的间隔时间
    weight 2  ---利用权重值和优先级进行运算,从而降低主服务优先级使之变为备服务器
 }
 #一个vrrp_instance就是一个虚拟路由器的实例
 vrrp_instance VI_1 {

 # 指定 keepalived 的角色,MASTER 表示此主机是主服务器,BACKUP 表示此主机是备用服务器
     state MASTER  

 # 指定网卡
     interface ens33
  #虚拟路由标识,这个标识是一个数字,同一个vrrp实例使用唯一的标识。 # 即同一vrrp_instance下,MASTER和BACKUP必须是一致的 # ID还是虚拟MAC最后一段地址的信息,取值范围0-255 virtual_router_id 51

     # 定义优先级,数字越大,优先级越高(0-255)。
     # 在同一个vrrp_instance下,MASTER 的优先级必须大于 BACKUP 的优先级
     priority 100

 # 设定 MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位是秒
     advert_int 1
 # 通信认证机制,这里是明文认证还有一种是加密认证
     authentication {
         auth_type PASS
         auth_pass 1111
     }
 #如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式,阿里云ECS好像只允许单播
unicast_src_ip 192.168.65.100 #本机
     unicast_peer {
         192.168.65.101  
     }
track_script {     #调用脚本
        check_nginx
     }
 # 设置虚拟VIP地址,一般就设置一个
     virtual_ipaddress {
         192.168.65.99
     }
 }

BACKUP

! Configuration File for keepalived
 全局配置
 global_defs {
 #邮件通知信息
 notification_email {
      acassen@firewall.loc
      failover@firewall.loc
      sysadmin@firewall.loc
    }
 #定义发件人
 notification_email_from Alexandre.Cassen@firewall.loc
 #smtp服务器地址
 smtp_server 192.168.200.1
    smtp_connect_timeout 30
 #路由标识
 router_id LVS_DEVEL
 vrrp_skip_check_adv_addr
   # vrrp_strict 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
    vrrp_garp_interval 0
    vrrp_gna_interval 0
 }
vrrp_script check_nginx {     #定义脚本
    script "“/etc/keepalived/check_nginx.sh"  --- 表示将一个脚本信息赋值给变量check_nginx
    interval 3    --- 执行监控脚本的间隔时间
    weight 2  ---利用权重值和优先级进行运算,从而降低主服务优先级使之变为备服务器
 }
 #一个vrrp_instance就是一个虚拟路由器的实例
 vrrp_instance VI_1 {

 # 指定 keepalived 的角色,MASTER 表示此主机是主服务器,BACKUP 表示此主机是备用服务器
     state BACKUP

 # 指定网卡
     interface ens33
  #虚拟路由标识,这个标识是一个数字,同一个vrrp实例使用唯一的标识。 # 即同一vrrp_instance下,MASTER和BACKUP必须是一致的 # ID还是虚拟MAC最后一段地址的信息,取值范围0-255 virtual_router_id 51

     # 定义优先级,数字越大,优先级越高(0-255)。
     # 在同一个vrrp_instance下,MASTER 的优先级必须大于 BACKUP 的优先级
     priority 99

 # 设定 MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位是秒
     advert_int 1
 # 通信认证机制,这里是明文认证还有一种是加密认证
     authentication {
         auth_type PASS
         auth_pass 1111
     }
 #如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式,阿里云ECS好像只允许单播
unicast_src_ip 192.168.65.101 #本机
     unicast_peer {
         192.168.65.100  
     }
track_script {     #调用脚本
        check_nginx
     }
 # 设置虚拟VIP地址,2机要一样
     virtual_ipaddress {
         192.168.65.99
     }
 }

配置IP转发

root> echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
root> sysctl -p
root> net.ipv4.ip_nonlocal_bind = 1

启动服务

启动 MASTER 和 BACKUP 的 keepalived 服务
 $ sudo systemctl start keepalived
 设置开机启动
 $ sudo systemctl enable keepalived

此时查看 MASTER 的网卡,我们的虚拟IP已经成功配置。

漂移规则如下:

  1. 默认使用 MASTER 服务器(192.168.65.100),虚拟 IP 为 192.168.65.99,此时 MASTER 服务器会有 2 个IP。
  2. 当 MASTER 出问题时,IP 会漂移到 BACKUP 服务器(192.168.65.101),此时 BACKUP 服务器会有 2 个IP。
  3. 当 MASTER 重新启动后,虚拟 IP 又会漂移回 MASTER 服务器。(抢占模式)

如何查看呢?

#在MASTER上运行 
$ tcpdump -i ens33 vrrp -n
11:42:13.526952 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
 11:42:14.528063 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
 11:42:15.529182 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
 11:42:16.532483 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20

这表明 MASTER 在向 BACKUP 广播,MASTER 在线。此时虚拟 IP 时挂在 MASTER 上。
我们可以测试一下:

首先,停止 MASTER 的 keepalived ,如果 MASTER 停止 keepalived,虚拟 IP 会漂移到 BACKUP 服务器上。

$ sudo systemctl stop keepalived

然后,在 MASTER 服务器上查看 VRRP 服务

[root@localhost keepalived]# tcpdump -i ens33 vrrp -n
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
 11:45:24.572246 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20
 11:45:25.572719 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20
 11:45:26.574943 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20
 11:45:27.577825 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20

可以看到,成功飘逸到BACKUP服务器,我们再恢复一下

[root@localhost keepalived]# systemctl start keepalived.service 
 [root@localhost keepalived]# tcpdump -i ens33 vrrp -n
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
 11:46:25.711037 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
 11:46:26.714028 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20

Keepalived 的热备实现成功,接下来,我们就要结合nginx, 需要写个脚本,判断nginx是否正常,否则将飘逸到BACKUP。

监控脚本如下,需要给文件执行权限:

!/bin/bash
 A=`ps -C nginx --no-header | wc -l`
 if [ $A -eq 0 ];then
     systemctl start nginx.service
     sleep 3
         if [ `ps -C nginx --no-header | wc -l` -eq 0 ];then
     killall keepalived
     fi
 fi

然后我们再在keepalived的配置文件中,加上脚本的执行,可以看前面的配置文件代码,有2段 check_nginx ,就是用来实现的。

我们来测试,当nginx宕机时,能否漂移到BACKUP

目前是使用MASTER

[root@localhost keepalived]# tcpdump -i ens33 vrrp -n
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
 11:56:00.351183 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
 11:56:01.355938 IP 192.168.65.100 > 192.168.65.101: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20

停掉NGINX 后

[root@localhost keepalived]# systemctl  stop nginx
 [root@localhost keepalived]# tcpdump -i ens33 vrrp -n
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
 11:57:36.903199 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20
 11:57:37.905001 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20
 11:57:38.905284 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20
 11:57:39.906674 IP 192.168.65.101 > 192.168.65.100: VRRPv2, Advertisement, vrid 51, prio 99, authtype simple, intvl 1s, length 20

我们可以看到,停掉后,当脚本2秒一次去检查的时候,就会漂移到BACKUP,到此,我们的高可用方案就完成了。

另外要说的几点:

1、我们实现的环境都是虚拟ip,目前大多数服务器都是使用 阿里云等的 ECS服务器,默认是不支持这样使用keepalived的,阿里云有自己的一套负载均衡方案,可以直接购买使用, 或者要实现,就要向阿里云申请ip,才能使用单播keepalived。