.mil 域名网站有哪些,如何看别人网站用什么做的,网站续费文档,四川省建设厅网站川北医学院nf_conntrack (在老版本的 Linux 内核中叫 ip_conntrack )是一个内核模块#xff0c;用于跟踪一个网络连接的状态
一旦内核 netfilter 模块 conntrack 相关参数配置不合理#xff0c;导致 nf_conntrack table full #xff0c;就会出现丢包、连接无法建立的问题
这个问题其…nf_conntrack (在老版本的 Linux 内核中叫 ip_conntrack )是一个内核模块用于跟踪一个网络连接的状态
一旦内核 netfilter 模块 conntrack 相关参数配置不合理导致 nf_conntrack table full 就会出现丢包、连接无法建立的问题
这个问题其实是老问题了之前也听说过但都是左耳进右耳出直到上周线上出现故障了才真正的对这个问题有了一个较为全面的了解
于是我把我真实遇到的情况总结成今天这篇文章让大家对这个问题产生的原因和背后细节有一个较好的了解
1.案例现象
上周周末我们打算对 A 服务进行压测在压测过程中测试小伙伴反馈后端服务挂了
登上机器查看一下服务器负载发现正常没有出现因负载过高导致服务器宕机的情况
然后查看 A 服务的日志没有看到相关的请求记录没有发现异常
接下来打算查看一下系统日志/var/log/messages
这时候才发现了不对劲系统日志上记录了大量错误信息如下
Feb 18 14:02:17 localhost kernel: nf_conntrack: table full, dropping packet
Feb 18 14:02:17 localhost kernel: nf_conntrack: table full, dropping packet
Feb 18 14:02:17 localhost kernel: nf_conntrack: table full, dropping packet
Feb 18 14:02:17 localhost kernel: nf_conntrack: table full, dropping packet
Feb 18 14:02:22 localhost kernel: nf_conntrack: table full, dropping packet
Feb 18 14:02:22 localhost kernel: nf_conntrack: table full, dropping packet看打印出来的信息应该是这个压测时候的高并发连接触发了 nf_conntrack 保护机制——table 满了之后就开始 drop packet
2.定位问题
根据系统日志可以基本定位到是 nf_conntrack 的问题我们先来看看什么是 nf_conntrack
何为 nf_conntrack
nf_conntrack 从名字上看是 connection tracking 它是一个内核模块用于跟踪网络连接的状态
下面这个网站记录了有关这个模块的相关参数的含义有兴趣的可以上去看看
https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt
nf_conntrack 与 iptables 有关用来计算服务器上的 iptables 规则最常见的两个使用场景是 iptables 的 nat 模块和 state 模块
我们知道iptables 中 nat 模块的作用就是根据规则来修改目的地址或源地址
但光修改地址还不行我们还需要到达的包能够路由到发请求的服务器这时候就需要通过 nf_conntrack 来找到 nat 修改前那个连接的记录
而 state 模块通过 nf_conntrack 记录的连接状态NEW/ESTABLISHED/RELATED/INVALID 等来匹配防火墙过滤规则
我们可以先看看 conntrack 的跟踪信息记录我们可以在/proc/net/nf_conntrack中看到已经被跟踪的连接
cat /proc/net/nf_conntrackipv4 2 tcp 6 431930 ESTABLISHED src192.168.149.131 dst192.168.149.130 sport11638 dport4505 src192.168.149.130 dst192.168.149.131 sport4505 dport11638 [ASSURED] mark0 zone0 use2可以看出2 是 ipv4 的协议代码网络层6 是 tcp 的协议代码传输层这里 conntrack 可以跟踪 tcp/udp/icmp等各种协议类型
ipv4 2
tcp 6431930 则是该连接的生命周期默认是五天在收到新包之前该值会逐渐变小如果收到新包该值会被重置一下然后又开始重新计时
431930ESTABLISHED 是连接状态不是所有协议都有例如 udp
ESTABLISHED接下来就是四元组第一个地址四元组源地址和目标地址以及端口是在原始方向上记录的地址即发起方发送的地址
src192.168.149.131 dst192.168.149.130 sport11638 dport4505第二个四元组是 conntrack 希望在收到来自对等方的答复时看到的内容
src192.168.149.130 dst192.168.149.131 sport4505 dport11638最后的 ASSURED 就是该状态已经确认
[ASSURED]nf_conntrack 是如何存储连接信息的
上面部分介绍了 nf_conntrack 模块的作用——追踪连接
接下来该介绍 nf_conntrack 模块是怎么存储这些 track 信息的
我们首先需要知道nf_conntrack将每一条连接信息都 track 到一个哈希表里面hash table一条 conntrack 连接信息也称条目entry
哈希表中的最小存储单位称作 哈希桶bucket哈希表的大小称作 HASHSIZE所以哈希表有 HASHSIZE个 bucket
bucket 的大小对应 nf_conntrack 模块中的nf_conntrack_buckets值
而每个 bucket 包含一个链表link list每个链表都能够存放若干条 entrybucket size
nf_conntrack_max 则表示系统最大允许连接跟踪数即 entry 的个数
#nf_conntrack_max等于 bucket 个数乘上每个 bucket 的大小
nf_conntrack_max HASHSIZE * bucket size当有新的数据包到来时内核是如何判断这条连接信息是否被 track 到的
内核提取此数据包信息(源目IPport协议号)进行 hash 计算得到一个 hash 值在哈希表中以此 hash 值做索引索引结果为数据包所属的 bucket。这一步 hash 计算时间固定并且很短遍历 hash 得到所属的 bucket查找是否有匹配的 entry。这一步是比较耗时的操作bucket size 越大遍历时间越长如果没有匹配到则就新建
理想情况下每个 bucket 下 link list 只存储一条 entry即 bucket size 1这样查询效率是最高的每次查询追踪记录的时候都是完美的 O(1) 的效率
但如果一个 bucket 存放一个 entry这样会导致内存消耗非常大
官方指出每个 entry 会占用大概 300 字节的空间如果一个 bucket 存放一个 entry那么整个哈希表的大小就等于总 entry 的大小 假设一个 bucket 存放一个 entry我们设置 nf_conntrack_max 12262144就意味着哈希表可以存放12262144条 entry 这样我们会需要12262144308字节 12262144308/(1024*1024) 3508.22753906MB 大约3个G的内存 一般服务器配置高点的32G内存或者64G光是给 connection track 就达到了 3G更何况其中有些连接还是没有实际意义的已经被释放掉的 time_wait 的连接
那么一个 bucket 里应该存放多少条 entry 呢
我们看下官方的解释官方一般推荐一个 bucket 里存放四条 entry nf_conntrack_max nf_conntrack_buckets *4如果一个 bucket 存放过多的 entry就意味着每个 bucket 中的 link list 会非常长会影响 hash 查询效率
所以一个 bucket 里存放四条 entry兼顾时间和存储空间
3.解决问题
回到遇到的问题既然报错是nf_conntrack: table full, dropping packet
那就意味着系统的连接跟踪表满了我们有如下几种方法可选请大家可以结合自己服务器情况来选择使用
关闭防火墙
对不直接暴露在公网也不使用 NAT 转发的服务器来说关闭 Linux 防火墙是最简单的办法还能避免防火墙/ netfilter 成为网络瓶颈
#以 CentOS 7 为例
systemctl stop firewalld
systemctl disable firewalld修改 iptables 规则
对于需要防火墙的机器可以设置 NOTRACK 规则减少要跟踪的连接数
对于一些不需要 track 的连接针对对应的 iptables 规则加一个 notrack 的动作
# 表示凡是不跟踪的连接统统放行
# iptables 处理规则的顺序是从上到下如果这条加的位置不对可能导致请求无法通过防火墙
iptables -I INPUT 1 -m state --state UNTRACKED -j ACCEPT-j notrack把不需要 track 的 iptables 直接 notrack那自然就不会去占 hashtable 空间了更不会报错了
优化内核参数
一般来讲有下面两个逻辑
哈希表扩容nf_conntrack_buckets、nf_conntrack_max让哈希表里面的元素尽快释放超时相关参数
对于nf_conntrack_buckets 和 nf_conntrack_max的值官方给了一个推荐大小 nf_conntrack_buckets - INTEGER the default size is calculated by dividing total memory by 16384 to determine the number of buckets but the hash table will never have fewer than 32 and limited to 16384 buckets. For systems with more than 4GB of memory it will be 65536 buckets. This sysctl is only writeable in the initial net namespace. nf_conntrack_max - INTEGER Size of connection tracking table. Default value is nf_conntrack_buckets value * 4 可以看到nf_conntrack_max与宿主机的内存相关有个默认算法
#其中 x 为 CPU架构值为 32 或 64
CONNTRACK_MAX RAMSIZE (in bytes) / 16384 / (x / 32)假设宿主机架构为 64 位且内存为 64GB所以nf_conntrack_max值如下
CONNTRACK_MAX 64 * 1024 * 1024 * 1024 / 16384 / (64 / 32) 2097152又因为nf_conntrack_max nf_conntrack_buckets value * 4
nf_conntrack_buckets 2097152 / 4 524288nf_conntrack_max 2097152 nf_conntrack_buckets 524288PS要根据自身服务器配置情况来进行配置切勿一刀切
对于超时时间下列给出一些官方默认参数供大家参考结合自身服务器情况进行修改
nf_conntrack_tcp_timeout_established默认 432000 秒5天
代表 nf_conntrack 的 TCP 连接记录时间默认是五天五天后该记录就被删除掉
攻击者可以根据这个参数与你的服务器三次握手一建立就关闭 socket分分钟把你的连接跟踪表打爆
net.netfilter.nf_conntrack_icmp_timeout默认 30s
谁家 ping 等 30s 才算超时
nf_conntrack_tcp_timeout_syn_sent默认 120s
谁家程序的 connect timeout 需要 120s
nf_conntrack_tcp_timeout_last_ack默认 30s
被动关闭方发 FIN 后如果一直收不到对面的 ACK 或 RST会不断重发直到超时才 CLOSE
nf_conntrack_tcp_timeout_time_wait默认 120s
大家都知道 TIME_WAIT其实就是为了四次挥手的时候让数据包能够收收尾现在网络环境好了可以设置成 60s没必要对 TIME_WAIT 的连接跟踪这么长时间