[转]你真的了解nf_conntrack么?

ncr_conntrack调优实践

女主宣言

该文章出自HULK虚拟化团队(网络小分队),主要是基于在奥创版本升级过程中遇到的一个nf_conntrack问题展开的。该问题在日常开启了iptables的高并发运维场景中也会经常出现。该文章主要是结合实际场景分析了nf_conntrack模块存储在hashtable中的时间和空间复杂度,结合线上的使用场景给出了优化建议,希望该文能对大家的日常运维有所启发。

PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,点关注哦!

背景描述

最近在日常运维云平台的过程中,遇到了nf_conntrack table full,然后开始drop packet的问题。当然这个问题属于老问题了,在网上一搜资料也能搜到一大堆,但是真正深入研究的文章没多少,浅尝则止的居多。所以今天针对这个现场,我们深入分析一下这个模块的一些技术细节,让大家对这个问题的产生原因和背后细节能有更好的了解。

首先看看我们的问题现场,看看log

Dec 14 15:00:05 w-openstack08 kernel: nf_conntrack: table full, dropping packet

Dec 14 15:00:05 w-openstack08 kernel: nf_conntrack: table full, dropping packet

Dec 14 15:00:05 w-openstack08 kernel: nf_conntrack: table full, dropping packet

Dec 14 15:00:05 w-openstack08 kernel: nf_conntrack: table full, dropping packet

Dec 14 15:00:05 w-openstack08 kernel: nf_conntrack: table full, dropping packet

Dec 14 15:00:05 w-openstack08 kernel: nf_conntrack: table full, dropping packet

Dec 14 15:00:05 w-openstack08 kernel: nf_conntrack: table full, dropping packet

我们的问题是出现在ansible更新M版本openstack的时候触发的问题,但是该问题的产生从这个问题的日志上看,与ansible中的一些具体步骤没啥关系,但是有个共同的关系应该是ansible的一些高并发的连接触发了nf_conntrack的保护性机制,table满了以后,开始主动drop packet。

所以这里就需要先了解一下nf_conntrack,该内核模块主要是干嘛的。

实际场景

nf_conntrack从名字上看是connection tracking,是内核模块中的连接追踪模块。与iptables有关。计算节点上的iptables的规则,是因为我们的neutron网络中使用了安全组,当前我们的计算节点上用了iptables filter表做包的最后一步过滤。

在iptables filter过滤packet的时候用了状态跟踪机制,我们使用 -state参数指定了两种userspace的状态,ESTABLISHED,RELATED,当使用状态跟踪机制的时候,我们就需要nf_conntrack模块来对每个连接进行tracking。

具体计算节点规则如下,我们的规则中针对ESTABLISHED 和RELATED的连接做了放行,那些不知道属于哪个连接的和没有任何状态的连接,一律drop掉。

[[email protected] /home/wangbaoping]# iptables -S|grep state

-A neutron-openvswi-i6db946b2-1 -m state --state RELATED,ESTABLISHED -m comment --comment "Direct packets associated with a known session to the RETURN chain." -j RETURN

-A neutron-openvswi-i6db946b2-1 -m state --state INVALID -m comment --comment "Drop packets that appear related to an existing connection (e.g. TCP ACK/FIN) but do not have an entry in conntrack." -j DROP

所以这里我们的nf_conntrack模块会对宿主机上所有经过该iptables的连接都进行跟踪。这里就需要知道具体跟踪是咋跟踪的,会记录连接的那些信息,最后会将这些信息怎么存储,又怎么查询怎么信息。

这里我们可以先看看conntrack的跟踪信息记录,我们可以在/proc/net/nf_conntrack中看到已经被跟踪的连接,如下:

[[email protected] /home/wangbaoping]# head /proc/net/nf_conntrack

ipv4 2 tcp 6 115 TIME_WAIT src=xx.xx.xx.xx dst=xx.xx.xx.xx sport=54585 dport=9000 src=xx.xx.xx.xx dst=xx.xx.xx.xx sport=9000 dport=54585 [ASSURED] mark=0 zone=3 use=2

ipv4 2 tcp 6 100 TIME_WAIT src=xx.xx.xx.xx dst=xx.xx.xx.xx sport=40460 dport=9000 src=xx.xx.xx.xx dst=xx.xx.xx.xx sport=9000 dport=40460 [ASSURED] mark=0 zone=3 use=2

ipv4 2 tcp 6 431999 ESTABLISHED src=xx.xx.xx.xx dst=xx.xx.xx.xx sport=42482 dport=80 src=xx.xx.xx.xx dst=xx.xx.xx.xx sport=80 dport=42482 [ASSURED] mark=0 zone=3 use=2

ipv4 2 tcp 6 85 TIME_WAIT

这里我们看看其中的一条ESTABLISHED状态的trace记录。

tcp 6 431999 ESTABLISHED src=xx.xx.xx.xx dst=1xx.xx.xx.xx sport=42482 dport=80 src=xx.xx.xx.xx dst=xx.xx.xx.xx sport=80 dport=42482 [ASSURED] mark=0 zone=3 use=2

tcp是跟踪的协议类型,6很明显是tcp的协议代码,这里conntrack可以跟踪tcp/udp/icmp等各种协议类型。这里431999 就是该连接的生命时间了,默认值是5天。在收到新包之前该值会逐渐变小,如果收到新包,该值会被重置一下,然后又开始重新计时。

接下来就是四元组了,接下来是反向连接的四元组,最后的ASSURED就是该状态已经确认。

场景分析

其实整体宿主机中conntrack跟踪的连接基本状态都已经是time_wait,因为上面的vm提供的都是web短连接服务,server端主动断开连接成功就会有个2MLS的time_wait,这些连接也都被track,该conntrack也会占用2分钟的时间。

这都不用并发太高的环境,比如我们的vm web每秒并发个100,2MLS的时间2分钟得生成260100=12000,基本上这一秒的并发会生成1万多的time_wait,conntrack记录。再按每条并发连接持续的时间长短,大概预估一下。

每天产生的time_wait状态的conntrack数是,就按个比较活跃的业务来说,一天也能产生大概5万多的conntrack记录。

我们可以通过查看nf_conntrack_count看看当前,在bjcc的53节点上nf_conntrack跟踪了多少连接,如下:

[[email protected] /home/wangbaoping]# sysctl net.netfilter.nf_conntrack_count

net.netfilter.nf_conntrack_count = 215168

差不多21万的conntrack记录。基本上97%的都是处于server主动断开并且处于time_wait状态的连接,3%是正在建立的establishted状态的连接。

[[email protected] /home/wangbaoping]# ss -s

Total: 363 (kernel 1225)

TCP: 34 (estab 24, closed 3, orphaned 0, synrecv 0, timewait 1/0), ports 0

Transport Total IP IPv6

* 1225 - -

RAW 0 0 0

UDP 2 2 0

TCP 31 31 0

INET 33 33 0

FRAG 0 0 0

这里就是个短连接不断积累的过程,不断地server主动断开,不断地timewait,这些都会被conntrack跟踪记录。所以一般默认的nf_conntrack_max=65535,很快就被塞满了。一旦塞满了就会随机的drop包。在外面看来就是丢包情况非常厉害。

原理剖析

前面都是说的nf_conntrack怎么记录我们的connection。慢慢就轮到了nf_conntrack怎么存储这些track记录。

nf_conntrack对connection的track最后都会扔到一个hashtable里面,这里就涉及到一个查询时间与存储空间的效率问题了。

我们肯定都希望将这些entry每一条都塞到一个哈希桶里,每个桶都只有一个link node,该node只存储一个connection entry。这样每次查询connection entry就是完美的O(1)的效率,多美好。

但是这样的存储空间要爆表了。

好吧,到这里先不说成本的问题,先说说如果真有这么多connection track连接,我们这个hashtable究竟要咋放这么多entry。

这里我们的都知道我们的entry最后会先经过hash,扔到我们的一定数量的hash桶里面。如果桶数量不等于entry数量的话,那一个桶里还得多放几个entry。

这里官方的hashtable处理冲突用的是链地址法,该冲突处理方法也是比较常用的地址冲突处理方法。桶里放得是头指针,然后相同key的node用单链表连起来。

这里hash桶的查找效率肯定是O(1)的,在hash桶里面是常用的link node list单链表。单链表的查询效率肯定是o(n)的,所以我们都希望每个entry放在一个桶里,我们希望最快的查询速度。

但是每个entry都放到桶里,内存消耗是非常大的。

因为看官方对conntrack entry的优化说明,每一条entry会占用大概300字节的空间。我们这里如果上来就分配一个超级大的hashtable,并且nf_conntrack_buckets == nf_conntrack_max 。

比如我们设置nf_conntrack_max = nf_conntrack_max = 12262144,该参数的意思就是我们的hashtable非常大,并且每个桶只放一条entry,可以放12262144条connection entry。

这样我们会需要12262144308字节= 12262144308/(1024*1024) = 3508.22753906MB ,大约3个G的内存。。当然有余数是因为这个max值没有设置成2的幂次方。

我们总共就64的内存,光给一个connection track,并且track到的连接都是些没有实际意义的已经被释放掉的time_wait的连接。所以这样配置成本是有点高的。当然我们的服务器上不是这样的。

所以我们一般都选择hashtable + linknode list的方案。这样能在存储空间和查询效率之间取个平衡。

因为桶是直接内存占用,这里的内存分配是按nf_conntrack的struck结构体来分配的,可以稍微去看看源码中这个结构体就能看到有多庞大了。大约300字节。

每个桶里放的是该单链表的头指针,指针要的内存空间要比nf_conntrack结构体要的明显小太多了,一般这个与cpu架构和编译环境都有关系,这里一般就按8字节算了。这样会省很多存储空间

比如官方一般都推荐一个桶里放4条entry。所以官方的默认参数里面,你一般会看到nf_conntrack_max = nf_conntrack_buckets *4,四倍的关系

如果nf_conntrack_max 远远大于nf_conntrack_buckets ,就意味着每个桶里面会放非常长的单链表。。这样查询速率肯定是会有比较大影响的。

比如我们现在的服务器配置:

[[email protected] /home/wangbaoping]# sysctl -a|grep nf_conntrack_max

net.netfilter.nf_conntrack_max = 12262144

[[email protected] /home/wangbaoping]# sysctl -a|grep nf_conntrack_buckets

net.netfilter.nf_conntrack_buckets = 16384

我们创建了一个hashtable,该table设置了16384个桶。那就是每个桶里面可以存放 12262144/16384 = 748.421875,大约可以放750条entry。这样我们的entry查询延迟就比官方的大了200多倍。

其实这里我们对线上的修改都只是更改了nf_conntrack_max ,把这个值设置成12262144,但是没有改过nf_conntrack_buckets ,这个值足够大,足以满足我们的目前的connection entry日常产生记录。

因为我们的线上一般就是30万左右connection entry数。但是这不是个兼顾空间与时间的最优配置。

在官方建议中一般大于4GB的内存空间,默认nf_conntrack_buckets = 65536,如下。现在centos7.2版本中已经改成这个参数了。

nf_conntrack_max 默认四倍的关系。一个桶里放四个entry。兼顾时间和存储空间

[[email protected] /home/wangbaoping]# sysctl -a|grep nf_conntrack_buckets

net.netfilter.nf_conntrack_buckets = 65536

[[email protected] /home/wangbaoping]# sysctl -a|grep nf_conntrack_max

net.netfilter.nf_conntrack_max = 262144

但是在centos7.1中还是默认的1GB的内存空间配置。默认nf_conntrack_buckets = 16384,默认的nf_conntrack_max 4倍关系 65536,这个max值肯定是满足不了我们当前的业务记录的。所以得调大点。

还有一个影响conntrack积累记录的参数就是nf_conntrack_tcp_timeout_established ,该参数会跟踪一个记录5days,这太长了。当然这是官方推荐的时间。

调到一天等,但是我们的connection tracking记录中只有3%的是established状态的连接,所以该参数对降低线上table full丢包问题没啥太大影响。

nf_conntrack_tcp_timeout_established = 432000

总结

所以最后针对该内核模块的使用,有很多种方法。

1

拥抱高版本ovs

就是不用该模块了。这样的场景是在以后,比如说M版本支持ovs2.6,高版本ovs本身就支持在ovs层面做安全限制,不需要在用qbr这种蹩脚的设计了,这样宿主机就不用启用iptables,自然就不用connection track了。更不会有现在这个问题了。

2

修改iptables规则

继续用这个模块,但是我们直接在neutron 代码中改一下,针对这些状态机制的iptables规则做一个动作, -j notrack,这样的好处是治本,把不需要track的iptables直接notrack,那自然就不会去占hashtable空间了,更不会报错了。

3

优化核心参数

继续用这个模块。但是我们要对参数进行一下调优。参数得设置的更合理一些。

nf_conntrack_buckets 和nf_conntrack_max 的平衡关系就不说了,具体我们的max应该设置成多少呢?

这个与宿主机内存有关系,并且官方有个计算公式,

CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (x / 32)

这里我们的宿主机内存一般都是64GB,所以CONNTRACK_MAX = 64 102464 = 4194304,最大支持400多万,然后桶的数量就是四倍的关系。4194304/4 = 1048576

nf_conntrack_max = 4194304

nf_conntrack_buckets = 1048576

这样就ok了。已经远远大于我们现在业务conn track 记录数量了。

这样的配置,用在我们的业务环境中。比如53上

net.netfilter.nf_conntrack_count = 218570

如果换这个参数的话。

我们有100万个桶,20万左右的entry放进去足以,每个桶就一个entry,查询效率o(1),非常高。

同时效率高了,我们继续算算内存占用。前面已经说了nf_conntrack struck本身初始化就得占用300左右字节,我们的link node指针也就是占用个8个字节而已。

所以我们算算 内存占用 = 4194304 * 300 + 1048576 * 8 = 1266679808字节 = 1208M。一个G而已

对应我们64GB的空间占用这点内存,换个O(1)的iptables查询效率还是可以的。

看看当前可用mem还有8个G,还是可以接受的

[[email protected] /home/wangbaoping]# free -m

total used free shared buff/cache available

Mem: 64237 50988 8308 1284 4940 10751

Swap: 32255 803 31452

当前服务器上的配置前面我们已经算过了,内存占用 = 12262144 *300 + 16384 *8 = 3508.35253906M 大约3个G。

至于效率前面更已经算过了。时间等于 = o(n) + o(1) = o(n),这里的n = 12262144/16384 = 748.421875,而我们上面的配置中时间是o(1)的,现在的配置是我们优化后的配置的耗时700倍。

但是cpu真是太快了,700倍在cpu那里都不是个事。但是明显该优化后的参数再时间和存储空间两个维度都是优于线上的。

但是优化后的配置有个不足就是,同时支持track的连接数是400万。线上是1200万。意思就是如果我们的宿主机上track的connection到了无可救药的400万以上了。那就会触发丢包。

但是当前观察所有的业务下的conntrack数目都只是30万左右。并且track的都是一些time_wait状态的connection,如下面的shm08,无效的connection track比例达到了97%。。

[[email protected] /home/wangbaoping]# cat /proc/net/nf_conntrack|grep ESTABLISHED|wc -l

5125

[[email protected] /home/wangbaoping]# cat /proc/net/nf_conntrack|grep TIME_WAIT|wc -l

136767

所以到这里有两个选择,就是在tcp层面去消除time_wait太多的问题。这就选择范围太多了。主流的还是tcp_tw_recycle内核参数的使用等等。这里就不展开了。

第二个就是在改一下nf_conntrack_tcp_timeout_time_wait = 120,改的小点。大家都知道time_wait其实就是为了让包收收尾,以前的网络太烂,包的路由和传输都很慢。预留2分钟是为了让这些释放连接的包能在2分钟内顺利到达。现在网络环境这么好。我们connection track没必要跟踪这么长时间。设置成60s,我们的connection track数量立马就能降一半。

整体来说我们的max设置成400万,桶的数量100万,是在64G内存服务器上最优的解决方案,兼顾内存占用和查询效率。其他的timeout参数,我们iptables没必要对time_wait状态的连接tracking 2分钟之久。1分钟就行。establishted状态我们tracking 5天可以接受。

所以最后推荐配置如下:

nf_conntrack_max = 4194304

nf_conntrack_buckets = 1048576

nf_conntrack_tcp_timeout_time_wait = 60

原文網址:https://kknews.cc/news/xl6x2zo.html

原文地址:https://www.cnblogs.com/jianyungsun/p/12554455.html

时间: 2024-08-29 15:26:12

[转]你真的了解nf_conntrack么?的相关文章

可任意操作nf_conntrack的nf_sockopt_ops

内核与用户态通信的接口简直太多了,有时候如果非要将它们分个三六九等也是不合适的,比如臭名昭著的ioctl,一旦臭起来就抽到底了,没人说它得好.有时候它并非想象中的那么坏,绝大多数是因为人们误用了它们,然后哪位大师说了一句它不好,从此以后人们就随大师而去了...对于ioctl,对应到socket类型文件描述符上,就是get/setsockopt两个接口函数,其实我不明白从函数名称上区分操作类型和从命令类型上区分有什么不同,一个对于UNIX文件描述符统一的ioctl为何会在socket上衍生出两个函

Linux路由表的抽象扩展应用于nf_conntrack

思想 标准IP路由查找的过程为我们提供了一个极好的"匹配-动作"的例程. 即匹配到一个路由项.然后将数据包发给该路由项指示的下一跳.假设我们把上面对IP路由查找的过程向上抽象一个层次,就会发现,事实上它还能够有别的用.抽象后的表述为:以数据包的源地址或者目标地址为键值去查询一张表.查到结果项以后运行结果项指示的一个动作.一个结果项为: struct result_node { uint32 network; uint32 netmask; void *action; }; 以上这个思想

关于并发你真的了解吗?

关于并发你真的了解吗?(一) 本文仅代表带个人观点及理解,本人只是一个编程小菜鸟,如果有不对的地方.请大佬轻喷! 前言:对于很多工作时间短或者编程经验不足的程序员来说,大多数会觉得并发这个词离自己太遥远,之所以知道并发也不过是因为受那些技术大佬成天讨论并发等问题耳濡目染罢了.更有甚者,一些所谓的"项目经理".一边侃侃而谈"大数据","高并发处理"等等高级问题,一边理所当然的写出Select * 或者是毫无规范性的性能极差的代码.当然这也跟国内的大

危机!测试工程师真的要小心了

百度搜索:小强测试品牌 本文选自<小强软件测试疯狂讲义-性能及自动化>一书 转眼已经在测试行业混迹了数年,不论是从技术还是行业本身来看都发生了巨大进步,而对于测试工程师的危机也越来越清晰.一旦谈论到危机,可能有的人会觉得小题大作,其实,只有以正确的态度意识到危机,我们才能更好的进步,接受它要比排斥它更加明智. 就我自己和与朋友的交流中来看,测试工程师的危机主要集中在下面几个: 1) 集中外包化是趋势. 随着社会的发展,竞争的激烈,一切不以盈利为目的的公司都是耍流氓,公司为了提升利润必然会对非核

你真的懂软件测试吗?

所谓金山银四,又是一波求职月,不安的因素在悸动.测试行业也是如此,作为软件测试员的我也在寻求更好的职业机会,软件测试岗同时也在做筛选,所谓优胜劣汰. 那么面临跳槽季,想在测试行业大展身手的你,真的懂软件测试嘛?小黑板,划重点~ 1.基础知识掌握 这部分,属于对自身的基础能力考查.也是进入测试行业的标准,包括:软件测试原理.软件测试的测试方法了解(刚入行,先了解起来).掌握常见的测试工具(如:UI自动化测试工具TestWriter.开源测试工具QTP.selenium等)等. 2.测试流程掌握 新

当不再炒作大数据的时候,大数据时代就真的来了

从2015年开始,大数据就已经被移出了Gartner的新兴技术炒作曲线."Big Data"(大数据)一词最早于2011年8月出现在Gartner新兴技术炒作曲线中,当时Gartner预计大数据技术需要2年到5年才能进入企业的实际生产型应用中.从那以后,大数据就迅速被市场热炒,最终在2015年彻底在Gartner新兴技术炒作曲线中消失. 进入2016年,大数据已经进入了实际的企业生产应用,在切实推动企业向数字化转型.另一家市场调查公司IDC则强调,在未来5年中,全球的数据驱动型企业将获

nf_conntrack被启用导致服务故障

1.查看是否有 nf_conntrack 使用iptable -L -t nat  查看,注意!!!查看也会启用nf_conntrack,任何和nat有关的命令都会启用nf_contrack -L 查看iptable规则,默认查看filter表 我们现在用的比较多个功能有3个: 1.filter 定义允许或者不允许的 2.nat 定义地址转换的 3.mangle功能:修改报文原数据 使用 lsmod命令,发现,nf_conntrack被多个模块依赖,按照规则必须先移除依赖模块再移除自己 nf_c

Azure手把手系列 4:微软Azure真的贵吗?值得吗?

通过前面的文章,相信大家对Azure有了一个基础的认识,接下来,我们再来看下作为企业,选择公有云服务最重要的因素之一  价格.我们都知道所谓公有云,就是要让IT资源变成我们生活中类似于水电气的资源,按需使用,按时计费.说得明白点就是让IT的开销都花在真正的需求上面, 并且要让公有云的资源消耗尽可能的贴合需求,这样才能够尽可能的达到公有云的效果. 所以不难看出,选择合适的配置.对应合适的需求.再有较高质量的服务和价格,是公有云非常具体的综合能力体现.这里我们还是来看一个例子,中等性能的Linux虚

月入十万真的难吗?

这是朋友抛给我的“月入十万很难吗”问题,当时我就问他,“你是以雇员的身份来看这个问题,还是以老板的身份来看?” 朋友不明白我的意思,不怪他,早些年我也不会明白这句话的意思. 01 刚工作的时候,我看着在北上广打拼的朋友们工资动辄就是1万起,刚开始还互聊对方的月收入,过了两年都变成聊年薪了. 好像除了我还在拿四位数的工资外,他们月收入都是2万多,偶尔他们还会调侃我说,“幸好你是在三线城市,那点工资到北上广估计租完房子后,都不够吃饭的.” 那时候,真是嫉妒羡慕恨.似乎在我周边,某某人的月入两万就是一