一、概述
接上文,实际生产场景中,往往存在硬件资源数量的限制,此时需要设置DS节点复用RS节点。
所以往往最常见的架构如下图所示:
1) 3台主机组建真实服务器集群,即3个RS
2) 2个RS兼做DS,构建负载均衡机制
Client
│
│VIP:17.7.7.18
┌────────────────┼────────────────┐
┌──────┴───────┐ ┌──────┴───────┐ ┌──────┴───────┐
│ RS1/DS1 │ │ RS2/DS2 │ │ RS3 │
│7.7.7.11 │ │7.7.7.12 │ │7.7.7.13 │
└──────────────┘ └──────────────┘ └──────────────┘
配置与非复用相同的情况下:在 docker 环境测试通过,但在生产环境中存在 LVS 转发混乱的情况!
二、DS/RS复用流量死循环:症状描述
如果 LVS 主备都是 localnode(即DS/RS复用),并且 backup 的 LVS rules 已经启用(比如 keepalived),那么就会出现下面的情况:
client 发 SYN 包给 master DS
50% 机会 master DS 把包转给 backup DS(因为 backup DS 也是 RS)
因为 backup 的 LVS rules 已经启用,所以50%机会 backup 把包转给 master
master 收到包后,又把包转给 backup,然后陷入死循环。
三、DS/RS复用流量死循环:解决思路
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服务处理。
其他描述参考:
经过 DS1 的包,如果 mac address 不是 DS2 的,用 iptables 给包打 mark=i
经过 DS2 的包,如果 mac address 不是 DS1 的,用 iptables 给包打 mark=j
在 keepalived 配置 LVS 时使用 fwmark-service 来表示 virtual_server,不用三元组(ip,port,protocol)的方式
这样,如果是 DS 转发过来的包,就不会进入 LVS 进行负载(防止两个 DS 互相扔皮球,进入死循环),而是被 RS 服务处理。而客户端进来的包,就会进入 LVS 进行负载。
四、DS/RS复用流量死循环:解决方法
#VIP=192.168.10.55
VIP=10.128.190.248
VPORT=80
#MAC_Director1=00:0c:29:0c:a9:ca
#MAC_Director2=00:0c:29:24:ce:e7
MAC_Director1=34:73:79:20:ca:73
MAC_Director2=34:73:79:20:cb:83
# DS1 配置 iptables ,除了 DS2 以外的包,都设置 mark 为 3
iptables -t mangle -I PREROUTING -d $VIP -p tcp -m tcp --dport $VPORT -m mac \
! --mac-source $MAC_Director2 -j MARK --set-mark 0x3
# DS2 配置 iptables ,除了 DS1 以外的包,都设置 mark 为 4
iptables -t mangle -I PREROUTING -d $VIP -p tcp -m tcp --dport $VPORT -m mac \
! --mac-source $MAC_Director1 -j MARK --set-mark 0x4
# 查看表 mangle:(默认 iptables 查看的是 filter 表)
iptables -t mangle -L -n
firewall-cmd --info-ipset=lvs_mark_list
# DS1 配置 keepalived
virtual_server fwmark 3 {
...
}
# DS2 配置 keepalived
virtual_server fwmark 4 {
...
}
五、以上配置后,包处理流程就变成如下
client 请求,master DS 收到包后,打了 mark 为 3。
LVS 看到 mark=3 的请求,50% 自己的 RS 处理,50% 转发到 backup DS。
backup 收到包后,发现是 master 过来的,不设置 mark。所以这个包不会被 LVS 处理,而被 backup 上面的服务给处理了。
Redhat 7 之前用的是 Piranha 做 LVS 的 HA,7版本后用 Keepalived。Piranha 是不会启用 backup 的 rules的,所以不存在这个问题。
【注意事项】
防止系统重启导致 iptables 规则失效!