Keepalived LVS+DR合设配置方法以及存在的问题

  使用Keepalived可以很方便的配置LVS,而Keepalived实现高可用往往都是一主多从的模式,这样的话备机就处于standby状态,浪费了资源。我们可以将LVS和RS节点合设在一起,这样备机虽然不会作为LVS节点转发,但是也可以作为真实服务器提供服务,充分利用资源。

一、Keepalived配置LVS-DR模式

! Configuration File for keepalived

global_defs {
}

vrrp_instance VI_1 {
    state BACKUP              //nopreempt不抢占要求节点都为BACKUP
    interface wlan
    virtual_router_id 51      //同一个集群节点的virtual_router_id要一致
    priority 100              //主节点要比备节点的priority高
    advert_int 1              //vrrp组播时间间隔
    nopreempt                 //主机从故障状态恢复后不抢占备机
    notify_master "/etc/keepalived/master.sh"
    notify_backup "/etc/keepalived/backup.sh"
    notify_fault "/etc/keepalived/fault.sh"
    virtual_ipaddress {
        192.168.1.1/27 dev wlan
    }
    
}

virtual_server 192.168.1.10 80 {
    delay_loop 6
    lb_algo rr
    lb_kind DR
    #persistence_timeout 50
    protocol TCP

    real_server 192.168.1.11 80 {
        weight 100
        HTTP_GET {
            url {
              path /
              digest ff20ad2481f97b1754ef3e12ecd3a9cc
            }
            connect_timeout 3
            retry 3
            delay_before_retry 3
        }
    }
}

  上面是一份常见的Keepalived LVS-DR模式的配置。在LVS不与RS合设的情况下,这份配置是没有问题的。
  但是,如果LVS与RS合设,这个配置就会带来一个非常严重的问题: 乒乓现象

二、乒乓现象

  • 什么是乒乓现象
      客户端消息发送给主机LVS后,调度给备机;而备机的LVS收到主机转发的消息后,又调度回给主机;主机因为之前的调度记录,会再次转发给备机,双方之间来回踢皮球,形成一个无法自动停止的环路,很容易就引发网卡流量风暴,把网卡打爆。
  • 出现乒乓现象的必要条件
     1. LVS和RS合设
     2. 使用DR模式,备机LO网卡上要绑定VIP
     3. 备机要加载LVS转发规则
      而很不幸,为了加快故障切换的速度,Keepalived会在master和所有backup节点同时都加载LVS规则。所以,Keepalived LVS-DR与RS合设的场景下,满足上述3个条件,必然有1/4的概率会出现乒乓现象。
  • Keepalived LVS+DR合设乒乓现象

    《Keepalived LVS+DR合设配置方法以及存在的问题》 LVS主机请求数

《Keepalived LVS+DR合设配置方法以及存在的问题》 LVS备机请求数

  如上所示,仅仅是一个telnet发起的syn请求,就已经能造成如此巨大的转发量了,如果是生产环境,必然会引起网卡流量风暴。

三、如何解决合设带来的乒乓问题

  要想解决乒乓问题,只需要将引发乒乓现象的必要条件给破坏掉。很显然条件1和2都是不能改变的,不然这个问题本身也没有存在的意义了。那我们只能拿条件3开刀了。
  既然备机加载了LVS转发规则就会引发乒乓,那么能否让备机不加载规则呢?

  • 方法一:避免备机加载LVS规则
      Keepalived都是通过/etc/keepalived/keepalived.conf这个配置文件进行规则加载的。我们可以不将virtual_server的配置直接写死到keepalived.conf中,而是通过include引用的形式来引用其他路径下的文件:
include /etc/keepalived/*.conf

  而对于备机,我们可以在/etc/keepalived下创建一个目录,如vs_dir,利用notify_backup脚本将virtual_server配置挪到vs_dir中隐藏起来,避免Keepalived加载。当backup节点切换到master状态时,由notify_master节点将目录中隐藏的vs配置挪到/etc/keepalived下,使Keepalived可以正常加载。
  上面的办法虽然能解决问题,但是比较繁琐,也不利于故障快速切换。那么我们换个思路,在备机加载了LVS规则的情况下,要想解决问题,只需保证主机上转发过来的消息不进入备机的LVS转发,而是直接由备机的真实服务进行处理。

  • 方法二:使用fwmark标记
      iptables的mangle表可以对目标数据包加上mark标记,用于实现策略路由控制数据包的流向。我们在规则中指定对端LVS节点的mac地址,如果不是对端mac地址的请求,说明是来自客户端的请求,需要打上mark标记;如果是来自对端mac地址的请求,则说明是主机转发的请求,就不打标记。
      而刚好LVS也支持通过fwmark配置虚拟服务,替代场景的VIP:PORT方式,只对打了fwmark标记的数据包进行转发。二者结合起来即可实现只针对客户端过来的请求进行转发,乒乓问题迎刃而解!
      一次完整的客户端请求处理流程如下:
       首先客户端的请求到达LVS主机,先由主机上的iptables对请求数据包打上一个mark值为1的标记(mark值可为任意正整数),然后LVS上配置了fwmark为1的虚拟服务,这样被打上mark的数据包就可以正常被主机的LVS捕获,进入虚拟服务转发;如果请求被转发给了备机,因为是来自主机mac地址的请求,所以备机不会打mark,也就不会进入备机的虚拟服务转发,而是直接由备机的RS服务处理。
       iptables配置方法:
     LVS主机上配置iptables,其中$MAC_Director_B 表示备机的mac地址
# iptables  -t mangle -I PREROUTING -p tcp -m tcp -d $VIP --dport $VPORT -m mac ! --mac-source $MAC_Director_B -j MARK --set-mark 0x1

  LVS备机上配置iptables,其中$MAC_Director_A 表示主机的mac地址

# iptables  -t mangle -I PREROUTING -p tcp -m tcp -d $VIP --dport $VPORT -m mac ! --mac-source $MAC_Director_A -j MARK --set-mark 0x1

  keepalived.conf中virtual_server的配置

virtual_server fwmark 1 {
    delay_loop 6
    lb_algo wrr
    lb_kind DR
    #persistence_timeout 50
    protocol TCP

    real_server 192.168.1.10 80 {
        weight 100
        TCP_CHECK {
            connect_timeout 3
            retry 3
            delay_before_retry 3
        }
    }
    real_server 192.168.1.11 80 {
        weight 100
        TCP_CHECK {
            connect_timeout 3
            retry 3
            delay_before_retry 3
        }
    }
}

  注意,iptables中给数据包打上的mark值只是一个系统内核中数据结构,并不会实际改变数据包的内容,数据包ip头部中也没有mark的字段。所以备机上收到来自主机转发的请求中,是没有mark标记的,而备机的iptables中也限定了来自主机mac的请求不会打标记,所以请求是不会进入备机的LVS虚拟服务中,而是被RS服务直接处理。

《Keepalived LVS+DR合设配置方法以及存在的问题》 MARK target介绍

图片内容参考来自
https://www.frozentux.net/iptables-tutorial/chunkyhtml/x4389.html

  下面介绍的mark标记和lvs工作分别对应netfilter框架中的位置,应该会有助于理解fwmark为什么能解决乒乓问题

《Keepalived LVS+DR合设配置方法以及存在的问题》 netfilter框架

  如上图所示,对数据包打上mark标记是在mangle表的PREROUTING链中,而LVS捕获数据包是在filter表的INPUT链中。在netfilter框架中,数据包的流向是先经过PREROUTING链,再到INPUT链,所以打mark标记会先于LVS处理。

图片内容参考来自
http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.filter_rules.html

  • 方法3:使用REDIRECT重定向
      除了使用fwmark,还有一个办法让备机上收到主机转发的数据包不再进入备机的虚拟服务,那就是在备机LVS捕获到数据包之前,使用nat表中的REDIRECT直接将数据包目的地址重定向到本机127.0.0.1,这样备机的LVS也就无法捕获到这个数据包了,而是由备机的RS服务直接处理。注意,这个方法要求RS服务是全网监听,即必须同时监听在127.0.0.1才行。否则REDIRECT后备机无法处理。
      在备机的NAT表中配置REDIRECT规则,主机中无需配置。
# iptables -t nat -A PREROUTING -p tcp -m tcp -d $VIP --dport $PORT -j REDIRECT

  如果发生了主备切换,则需要在脚本中调整主备机中的这条iptables配置,将新主机中的配置清除,新备机中加上该配置。

  综合来看以上各种方法,更倾向于使用fwmark。方法一实现过于繁琐,也不利于故障快速切换。方法3需要在切换时更改对应角色的iptables配置,增加了切换的不稳定性。而fwmark在部署阶段配置好后则无需再变动,更为可靠。只是要注意防止系统重启导致iptables规则失效。

    原文作者:Mr萝卜
    原文地址: https://www.jianshu.com/p/612a55652ae8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞