LVS负载均衡软件在处理Netfilter/iptables连接状态跟踪机制时遇到的一个bug的说明

LVS这个开源项目的历史可能快有20年了,至今仍然很受欢迎,在国内众多大小公司有广泛的应用。
最近在工作中遇到的一个LVS软件的bug,这个bug很隐蔽,如果没有很大的流量负载时,很可能是发现不了它的。但也正是因为这个bug,很可能你的网站或服务的并发处理性能要大大折扣。
这个bug是LVS和Netfilter/iptables在一起使用时发生的,如果你的系统有很好的外部防护,未启用主机的系统防火墙,那么就也不会存在我下面要讲的问题。
接下来我从遇到的这个问题的现象讲起。

1、问题描述
我们的服务接口是由LVS做负载均衡的一组机器。在大批的访问请求过来时,发现LVS realserver节点的网络连接数量增长得异常快,也非常多。迅速达到单节点几万的级别了就。与此同时客户侧反馈说,接口的响应延时比较大。 我们调查了一下网络连接这块,被系统中的这个网络连接的状态和结果着实吓了一跳。如下图所示,全是FIN-WAIT-2状态的连接,不是大部分,除了ESTAB的之外,其它基本全部都是,每个realserver上能有几万个。

2、问题分析
我们都熟悉LVS的DR模式的工作机制,在LVS服务的director节点上提供一个vip地址,CIP/VIP/DIP/RIP这几个地址按设计逻辑进行交互,大体上是外部来的请求包都首先发给了这个director节点的vip地址,而响应数据包则是realserver直接发给客户端。director对收到的请求报文做一些必要的修改后,转发给后端的realserver节点处理。在这之后就是客户端的机器直接与我们的realserver节点建立TCP连接传输数据。
(1)在realserver上的连接停在FIN-WAIT-2状态到超时,说明realserver作为主动断开连接的一方,发出了FIN包,也收到了FIN包的ACK确认。但是,一直没收到客户端发来的FIN包。因此,总也无法进入TIME-WAIT状态,然后自动被释放。
(2)找一个测试机模拟客户端访问LVS的VIP服务端口
如下图所示,后缀.10的为测试客户端地址,后缀为.50的为LVS的VIP。这里做了模糊处理,实际上这两个地址并不是同一个网络中的,测试客户端是从远程访问过来的。
抓包显示:
  • 二者能正常的建立起TCP连接;
  • 是由LVS的realserver主动发出的FIN包断开连接;
  • 测试客户端收到FIN包后,立即回复了ACK和自己的FIN包。
异常的地方在于:下一个数据包居然是返回的ICMP Destination unreachable (Host administratively prohibited)
不仅如此,后续又反复收发了多个重传、重复的数据包,也反复抛出相似的错误报文。
也就是说,本该正常得由客户端发送给LVS的FIN包,虽然发出了(见下图的包5),但对方不但没收到,还直接给返回了一个ICMP主机路由不可达的报文!

到这一步为止,实际上双方间的有效连接已经断开了,但LVS侧的realserver上的连接停在了FIN-WAIT-2状态,客户端侧的连接停在了LAST-ACK状态,双方都只能等更长的时间才能以超时结束,并释放连接资源。

(3)问题很严重吗?
其实不是,虽然上面的报文中错误一大堆,但实际上的效果是LVS和客户端双方之间的数据通信居然未受明显影响,该提交的数据仍被成功提交上去了,仅仅是在要断开连接时,才抛的ICMP错误报文。
在访问请求的数量非常大时,来自客户端的请求仍然可以成功,只是响应时间和处理延时越来越明显了,而且LVS realserver节点上累积了越来越多的FIN-WAIT-2状态的异常断链。
因此,上面这个问题并不是很容易被发现。很可能正常使用了很久了,才因为一些特殊的事件,注意到这个问题。

3、问题的根源原因是什么
我们仔细看一下ICMP主机不可达的这个报文内容,如下Type:3,Code:10
这种报文在主机系统防火墙中设置了禁止访问的过滤规则时,是最经常遇到的。你要访问的一个主机端口,人家没授权,那么你得到的就是这么一个ICMP主机不可达(Host administratively prohibited)。意思就是主机不是真的不可达,只是在授权管理上对你禁止访问了。

那就显得更奇怪了,我们的测试客户端和LVS服务之间显然是有访问授权的,而且双方是先成功建立连接,传输数据的,要结束时倒说主机不可达,双方的连接就这么卡在那等待很久才能超时结束。

经过一番艰苦得查找,找到这样一份LVS HOWTO的技术资料,虽然旧了点,但资料的详尽程度让人吃惊,不过是英文的。
光是目录索引项可能就有几百项。
我重点学习了ICMP这一章节,其实看后才发现这不是一份严谨的技术资料,只是把很多比较有价值的问题讨论过程和结果整理并分享出来的。当然了,这里面很多问题的回答者之一,就是章大神——LVS他爸爸!
我把LVS ICMP这份英文资料中的最后一段翻译过来,如下所示。也正是这段资料给我们遇到的奇葩问题提供了一个解决方法,虽然仍然未给出合理的解释。
原文翻译如下:
35.6. Long sessions through LVS DR director terminated by icmp-host-prohibited (ICMP type 3 code 10)
Klaas's posting of a bug. We don't know what it's about yet.
Klaas Jan Wierenga k.j.wierenga (at) home (dot) nl 26 Mar 2007
我遇到了一个问题,在这里有时会通过HTTP终止一些长时间的MP3流式会话,因为LVS-DR director向客户端发送ICMP类型3代码10-主机不可达(icmp-host-prohibited)数据包(mp3 流)。 发生这种情况时,客户端停止发送数据包15分钟(LVS的TCP空闲会话超时?)
最初我怀疑是LVS director,但经过一番调查,我发现它从来不会发送icmp-host-prohibited(不在linux/net/ipv4/ipvs/*源文件中)。 唯一的另一种可能是netfilter发送它(在net/ ipv4/netfilter/ipt_REJECT.c:send_unreach(* pskb,ICMP_HOST_ANO)中找到),但是为什么在一个已经存在的,已经建立的和活动的连接上发送呢?
我的初始iptables的相关部分是(/etc/sysconfig/iptables):
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:RH-Firewall-1-INPUT - [0:0]
:OUTPUT ACCEPT [0:0]
-A FORWARD -j RH-Firewall-1-INPUT
-A INPUT -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state -m tcp --dport 80 --state NEW -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited COMMIT
在将端口80规则更改为下面的规则后,有效地禁用端口80上的连接跟踪,问题消失了。
-A RH-Firewall-1-INPUT -p tcp --dport 80 -j ACCEPT
最初,我在LVS director上做了这个iptables的更改,但是,真正的服务器有时会在已建立的连接上发送icmp-host-prohibited,而且在更改真实服务器上的iptables后,问题就消失了。
目前还不清楚为什么netfilter会在连接跟踪激活时决定在建立的连接上发送icmp-host-unreachable。 也许netfilter列表中的某个人可以对此有所了解。
later on following up: 26 Jun 2007
我从来没有想明白它。 它似乎是一个netfilter问题,因为当我更改我的防火墙规则(/etc/sysconfig/iptables)以禁用连接跟踪时,问题就消失了。
# Don't do connection tracking on port 80 and 8000 because sometimes it
# results in dropped connections due to ICMP_HOST_UNREACHABLE messages
#-A RH-Firewall-1-INPUT -p tcp -m state -m tcp --dport 80 --state NEW -j ACCEPT
#-A RH-Firewall-1-INPUT -p tcp -m state -m tcp --dport 8000 --state NEW -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp --dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp --dport 8000 -j ACCEPT
4、问题的答案
虽说是问题的答案,但却不知道为什么这个方法就能解决这个问题。
一个更合理的解释是:LVS软件在处理Netfilter/iptables的状态跟踪机制时,是有BUG的。
当你在LVS director和realserver上配置iptables的端口过滤规则时,一个很常用的配置方法就是像下面这样:
-A   INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A  INPUT -p tcp -m state -m tcp --dport 80 --state NEW -j ACCEPT
前一条规则是说已经处于ESTAB状态的连接,可以直接通过,不受访问限制。后一 条规则中的“--state NEW”的作用就是说如果是一个针对80端口的新访问请求,则给予放行。
上面这些配置方法,是再普通不过的了。但正像上面这个外国网友在2007年就遇到了的问题一样,只要你在过滤规则中使用了state连接状态跟踪机制,那你就中奖了。虽然不影响成功建立连接和通信,但LVS将不能正常断开客户端与realserver之间的链接。

解决办法就是:关掉你的系统防火墙,或者是过滤规则中不要使用state状态跟踪机制去处理新建连接,就像下面这样就可以了:
-A   INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A  INPUT -p tcp -m tcp --dport 80 -j ACCEPT

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值