运维排查篇 | Linux 连接跟踪表满了怎么处理

排查,linux,连接,跟踪,怎么,处理 · 浏览次数 : 338

小编点评

**生成内容时需要带简单的排版** **1. 排版标题** * 标题应清晰易懂,包含关键词。 * 使用标题标签来划分内容。 **2. 排版内容** * 使用标题标签将内容分组。 * 排版内容以标题为首,内容为子标题。 * 使用缩点等符号来缩短标题。 **3. 排版图片** * 排版图片与标题相关。 * 使用图片标签来将图片关联标题。 **4. 排版视频** * 排版视频与标题相关。 * 使用视频标签来将视频关联标题。 **5. 排版表格** * 排版表格以标题为首。 * 使用表格标签来将表格关联标题。 * 使用缩点等符号来缩短标题。 **6. 排版代码** * 排版代码以标题为首。 * 使用代码标签来将代码关联标题。 * 使用缩点等符号来缩短标题。

正文

nf_conntrack (在老版本的 Linux 内核中叫 ip_conntrack )是一个内核模块,用于跟踪一个网络连接的状态

 

一旦内核 netfilter 模块 conntrack 相关参数配置不合理,导致 nf_conntrack table full ,就会出现丢包、连接无法建立的问题

 

这个问题其实是老问题了,之前也听说过,但都是左耳进右耳出,直到上周线上出现故障了,才真正的对这个问题有了一个较为全面的了解

 

于是我把我真实遇到的情况总结成今天这篇文章,让大家对这个问题产生的原因和背后细节有一个较好的了解

 

案例现象

上周周末,我们打算对 A 服务进行压测,在压测过程中测试小伙伴反馈后端服务挂了

 

登上机器查看一下服务器负载,发现正常,没有出现因负载过高导致服务器宕机的情况

 

然后查看 A 服务的日志,没有看到相关的请求记录,没有发现异常

 

接下来打算查看一下系统日志(/var/log/messages)

 

这时候才发现了不对劲,系统日志上记录了大量错误信息,如下:

 

 

 

 

看打印出来的信息应该是这个压测时候的高并发连接触发了 nf_conntrack 保护机制——table 满了之后就开始 drop packet

 

看打印出来的信息应该是这个压测时候的高并发连接触发了 nf_conntrack 保护机制——table 满了之后就开始 drop packet

 

 

定位问题

 

根据系统日志可以基本定位到是 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中看到已经被跟踪的连接

 

 

 

 

 

可以看出,2 是 ipv4 的协议代码(网络层),6 是 tcp 的协议代码(传输层),这里 conntrack 可以跟踪 tcp/udp/icmp等各种协议类型

 

ipv4     2  
tcp      6

   

431930 则是该连接的生命周期(默认是五天),在收到新包之前该值会逐渐变小,如果收到新包,该值会被重置一下,然后又开始重新计时

 

431930

  

 ESTABLISHED 是连接状态,不是所有协议都有(例如 udp)

ESTABLISHED

 

接下来就是四元组,第一个地址四元组(源地址和目标地址以及端口)是在原始方向上记录的地址,即发起方发送的地址

 

 

 

 第二个四元组是 conntrack 希望在收到来自对等方的答复时看到的内容

 

 

 

最后的 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),每个链表都能够存放若干条 entry(bucket size

 

nf_conntrack_max 则表示系统最大允许连接跟踪数,即 entry 的个数

 

 

 

 

 

 

 

 

当有新的数据包到来时,内核是如何判断这条连接信息是否被 track 到的

 

  • 内核提取此数据包信息(源目IP,port,协议号)进行 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

 

 

 

 

 

如果一个 bucket 存放过多的 entry,就意味着每个 bucket 中的 link list 会非常长,会影响 hash 查询效率

 

所以一个 bucket 里存放四条 entry,同时兼顾时间和存储空间

 解决问题

回到遇到的问题,既然报错是nf_conntrack: table full, dropping packet

 

那就意味着系统的连接跟踪表满了,我们有如下几种方法可选,请大家结合自己服务器情况来选择使用

 

  • 关闭防火墙

对不直接暴露在公网,也不使用 NAT 转发的服务器来说,关闭 Linux 防火墙是最简单的办法,还能避免防火墙/ netfilter 成为网络瓶颈

 

 

  • 修改 iptables 规则

对于需要防火墙的机器,可以设置 NOTRACK 规则,减少要跟踪的连接数

 

对于一些不需要 track 的连接,针对对应的 iptables 规则加一个 notrack 的动作

 

 

 

-j notrack

 

把不需要 track 的 iptables 直接 notrack,那自然就不会去占 hashtable 空间了,更不会报错了

 

  • 优化内核参数

一般来讲有下面两个逻辑:

  1. 哈希表扩容(nf_conntrack_bucketsnf_conntrack_max

  2. 让哈希表里面的元素尽快释放(超时相关参数)

 

对于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与宿主机的内存相关,有个默认算法

 

 

假设宿主机架构为 64 位且内存为 64GB,所以nf_conntrack_max值如下:

 

 

 

又因为nf_conntrack_max = nf_conntrack_buckets value * 4

 

 

 

所以

 

 

PS:要根据自身服务器配置情况来进行配置,切勿一刀切!

 

对于超时时间,下列给出一些官方默认参数供大家参考,结合自身服务器情况进行修改

 

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 的连接跟踪这么长时间

 


感谢阅读,喜欢作者就动动小手[一键三连],这是我写作最大的动力

与运维排查篇 | Linux 连接跟踪表满了怎么处理相似的内容:

运维排查篇 | Linux 连接跟踪表满了怎么处理

nf_conntrack (在老版本的 Linux 内核中叫 ip_conntrack )是一个内核模块,用于跟踪一个网络连接的状态 一旦内核 netfilter 模块 conntrack 相关参数配置不合理,导致 nf_conntrack table full ,就会出现丢包、连接无法建立的问题

日常Bug排查-改表时读数据不一致

前言 日常Bug排查系列都是一些简单Bug的排查。笔者将在这里介绍一些排查Bug的简单技巧,同时顺便积累素材。 Bug现场 线上连续两天出现NP异常,而且都是凌晨低峰期才出现,在凌晨的流量远没有白天高峰期大。而出问题的接口又是通常的业务请求。于是,很自然的,我们就想凌晨有什么特殊的运维动作,翻了下时

记一次Native memory leak排查过程

路由计算服务是路由系统的核心服务,负责运单路由计划的计算以及实操与计划的匹配。在运维过程中,发现在长期不重启的情况下,有TP99缓慢爬坡的现象。此外,在每周例行调度的试算过程中,能明显看到内存的上涨。

教你处理数仓慢SQL常见定位问题

摘要:通常在运维监控出现CPU使用率较高、P80/P95指标较高、慢SQL数量上升等现象,或者业务出现超时报错时,优先应排查是否出现慢SQL。 本文分享自华为云社区《GaussDB慢SQL常见定位处理手段》,作者:酷哥。 关键指标 通常在运维监控出现CPU使用率较高、P80/P95指标较高、慢SQL

记一次线上Redis内存占用过高、大Key问题的排查

问题背景 在一个风和日丽的下午,公司某项目现场运维同学反馈,生产环境3个Redis的Sentinel集群节点内存占用都很高,达到了17GB的内存占用量。 稍加思索,应该是某些Key的Value数据体量过大,占用了过多的内存空间,我们在使用Redis的过程中,单个Value或者单个集合中的元素应该保证

[转帖]MySQL 内存泄露怎样检查

MySQ使用内存上升90%!在运维过程中50%的几率,会碰到这样的问题。算是比较普遍的现象。 MySQL内存使用率过高,有诸多原因。普遍的情况是因为使用不当导致的,还有mysql本身的缺陷的导致的。到底是那方面的问题,那就需要一个一个进行排查。 下面介绍排查思路: 1.参数配置需要确认。是否内存设置

[转帖]【SOP】最佳实践之 TiDB 业务写变慢分析

https://zhuanlan.zhihu.com/p/647831844 前言 在日常业务使用或运维管理 TiDB 的过程中,每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题。这类问题大部分情况下都具有一定的规律可循,通过经验的积累可以快速的定位和优化。但是有些情况下不一定很好排查

[转帖]Redis检索性能不足,改造rsbeat解决历史慢日志跟踪

https://www.sohu.com/a/313061840_411876 作者介绍 刘宇,甜橙金融创新中心基础技术架构师,拥有9年IT从业经验、9年数据库开发运维经验、4次大型营销活动经验。目前关注容器、分布式数据库技术等基础技术。 在线上排查redis性能问题时,从redis中找进行优化是一

贝叶斯算法人生

哈喽大家好,我是咸鱼 之前看到过耗子叔写的一篇文章《程序算法与人生选择》,这篇文章中耗子叔结合计算机中的经典算法(排序、动态规划等等),让大家在人生道路的选择上获得了一些启发 我最近看了一些关于贝叶斯思想的文章,觉得还挺有感触的,于是打算写一篇相关的文章 今天这篇文章不会跟大家讲贝叶斯公式的推导 而

[转帖]运维工作常用SQL命令大全【收藏版】

运维工作常用SQL命令大全【收藏版】 https://www.modb.pro/db/65429 1、查看表空间使用率 set line 220select total.tablespace_name,round(total.MB, 2) as Total_MB,round(total.MB - f