连接跟踪流量统计这是Linux网络运维里一个特别容易被忽视但关键时刻能救命的角落。很多人搞iptables、搞防火墙规则精通得很一说到“你线上每秒多少新建连接连接表占用多少到底哪个IP在持续往外发包”就哑火了。原因很简单连接跟踪conntrack和流量统计这两件事平时不会主动出现在监控面板上等出了事故你才想起去查往往已经晚了。这篇东西我把它定位成一篇实操经验汇总。我不打算从头讲netfilter的论文级原理更多是站在一个长期跟连接表、计数器、NAT规则打交道的老运维视角把连接跟踪是怎么回事、流量统计到底有哪几条路可以走、每一步怎么落地、踩过哪些坑一次说清楚。适合刚接手公司网关、负载均衡或者K8s节点的同行也适合那些被“conntrack表满了”折磨过的新手。看完你至少能自己搭一套简单但可靠的流量统计脚本也能在连接表异常时快速定位方向。1. 连接跟踪到底在干什么为什么流量统计绕不开它1.1 连接跟踪的本质内核里的“状态记账本”连接跟踪全称connection tracking是Linux内核netfilter框架提供的一项基础能力。它的核心工作是把经过主机的数据流抽象成一条“连接”记录这条连接的五元组信息协议、源IP、源端口、目的IP、目的端口连同当前所处的状态NEW新建、ESTABLISHED已建立、RELATED关联连接比如FTP的数据通道、INVALID无效。打个比方你就懂了。连接跟踪表就像餐厅前台的服务员每一桌客人进来他会记一下桌号、人数、点没点菜、吃到哪个阶段。后面上菜、加单、结账全靠这本账。没有这个账本防火墙的state规则没法做——你凭什么判断这个包是回应之前的请求还是外部主动打进来的新攻击NAT也一样源地址转换后回程的包要能逆转翻译回去必须查连接跟踪表里存的映射关系。所以只要你的机器做了NAT、开了防火墙并且用了state/ct状态匹配、或者跑了Docker、Kubernetes这种重度依赖网络策略的容器平台连接跟踪就一定是开启的。1.2 连接跟踪表和流量统计的关系连接跟踪表本身不统计字节数。它只管“谁跟谁在通信现在什么状态”。但正因为它的存在内核可以在连接创建、更新、销毁的各个生命周期节点上天然挂钩各种计数逻辑。这就是为什么我们在iptables规则里能看到-c计数器在nftables里能定义counter在conntrack工具里能查到bytes和packets字段。换句话说连接跟踪给了你两个维度的数据一个是连接数横向规模一个是流量字节纵向体量。这两个维度合在一起才能回答运维里最常问的“谁在消耗带宽”“谁在疯狂发起连接”“NAT网关的负载是否到了瓶颈”。1.3 什么时候你会真正需要做流量统计我遇到过好几种典型场景逼着你必须认真做连接跟踪流量统计第一种公司出口NAT设备领导想搞清楚每个部门、每个应用占了多大带宽。这时候你得按源IP聚合流量光看交换机的端口流量没有任何意义。第二种后端服务突然被大量异常请求打满但前端所有QPS指标都是正常的。查了半天发现是某个内网服务在跟外网建立大量短连接连接表被打爆了。这时候你得看清楚到底哪个进程、哪个目的IP在制造连接风暴。第三种做安全审计。要回溯某段时间某个IP的往来流量连接跟踪日志是最好的“黑匣子”。这些场景没有一套顺手可用的连接跟踪流量统计手段基本就是抓瞎。2. 流量统计的常见实现路径——三选一看你有什么牌2.1 路径一内核计数器的被动统计iptables/nftables自带这是最朴素也最可靠的办法。iptables的每条规则自带两个计数器packets和bytes。你只需要把统计用的规则放在合适位置内核会默默帮你累加数据。它的优势在于不需要额外开服务不占额外CPU数据是内核精确计数的不丢包不采样。非常适合做“总量统计”和“按固定维度聚合统计”比如按源IP段、目的端口、协议来查流量。但它的短板也很明显聚合维度不够灵活。你写了十条规则按十个IP统计那以后想按“IP和端口组合”查就得加规则计数器是累计值想要速率必须拉差值后自己算另外iptables计数器在规则被刷新或者机器重启后会清零需要配套的持久化采集方案。2.2 路径二连接跟踪日志的被动采集基于日志的大数据统计内核提供了一个开关net.netfilter.nf_conntrack_acct开启后连接跟踪会对每条连接记录packets和bytes数据。你可以通过conntrack -L命令随时查看某条连接已经传了多少字节、多少个包。更进一步可以用ctnetlink机制把连接事件新建、更新、销毁推送到用户态通过ulogd2这类工具落日志或者自己写一段C/Python用netlink库接收消息。每条连接的字节数、包数都能被记录到。好处是统计维度非常自由——你可以存下来做离线分析、按任意字段group by也可以回溯历史某条连接的流量。代价是量大的机器上日志会产生海量事件磁盘和CPU都有压力实时性弱于计数器方案而且如果连接长时间不断开字节数只累计不输出需要按超时兜底。2.3 路径三流量采样与镜像分析NetFlow/sFlow/pcap旁路这条路严格来说已经不算连接跟踪流量统计了但实际运维里经常拿来补充。思路是把流量旁路出来用采样协议sFlow/NetFlow或者全量抓包pcap的方式交给外部分析器比如ELK、SQL数据库做聚合。优势是灵活、不碰生产路径、能拿到L7应用层信息劣势是需要额外部署硬件交换机支持sFlow还好纯服务器环境下还得做分光器或者端口镜像成本高采样有概率丢数据不适合对准确性极其敏感的对账场景。2.4 三条路径的选型对照维度内核计数器连接跟踪日志采样/镜像精确度精确精确抽样有误差实时性秒级主动拉取事件级推送秒级系统开销极低连接量大的主机有压力网络和存储压力高持久化需自己采集天然写入日志分析端存储聚合灵活度受限于规则配置任意维度SQL查询最灵活含L7适合场景网关/NAT计数器安全审计、连接级明细全链路监控、协议分析我个人的建议是日常监控、容量预警这种以路径一为主简单直接需要做安全审计或查历史连接时路径二配合conntrack工具临时看甚至靠journalctl慢慢捞规模大且有专业流量分析平台的再加路径三作为补充。3. 实操环节五种最常用的连接跟踪流量统计手段3.1 看一台机器当前活跃连接数摸清压力先别急着写统计脚本第一步应该是能快速回答“这台机器当前同时在跑多少条连接”。用一行命令# 查看当前连接跟踪总数 cat /proc/sys/net/netfilter/nf_conntrack_count # 查看系统允许的最大连接跟踪数 cat /proc/sys/net/netfilter/nf_conntrack_max当nf_conntrack_count接近nf_conntrack_max的时候事情就危险了——新连接会被内核直接丢弃表现为服务端口telnet不上但ping通业务日志里出现“connection reset”且有周期性。这个数字应该进你的监控系统告警阈值我一般设在最大值的80%左右。3.2 iptables计数器直接查流量最简单粗暴假设你想统计“访问本机8080端口的流量总量”直接加一条规则iptables -I INPUT 1 -p tcp --dport 8080注意我没给-j ACCEPT只是把规则挂在那里纯计数。因为INPUT链默认处理完所有规则会回到链策略只要不显式跳转计数规则不影响包的去向。这样加规则多少有点“脏”更干净的做法是建一条独立的统计链iptables -N TRAFFIC_STAT iptables -A INPUT -j TRAFFIC_STAT iptables -A TRAFFIC_STAT -p tcp --dport 8080随后想读取某条规则累计的包数和字节数iptables -L TRAFFIC_STAT -v -x-x参数很关键作用是让计数器输出精确数字而不是缩写成12K、34M这种带单位的格式方便脚本解析。这个参数至少在需要把数据丢给监控系统的场景里是必须的。3.3 按IP聚合统计流量拿脚本说话计数器方案最实用的形态是写一个脚本定时拉取计数器计算差值得到速率。我常用的逻辑如下# 清空指定链的计数器或重建规则全部归零 iptables -Z TRAFFIC_STAT # 确认规则存在后每分钟执行一次 # 先保存上一次的计数器读取当前值相减再除以间隔时间即得字节速率 prev_bytes$(cat /tmp/traffic_last.txt) curr_bytes$(iptables -L TRAFFIC_STAT -v -x -n | awk -v port8080 $3tcp $4dport {print $2}) echo $curr_bytes /tmp/traffic_last.txt rate_bytes$(( (curr_bytes - prev_bytes) / 60 ))实际生产环境里我会把这个逻辑编程成一段守护脚本输出成timestamp ip bytes bytes_per_sec的格式丢给Prometheus文本文件采集器或者写进InfluxDB。核心思路就是不要指望iptables给你速率它只给累计增量速率永远是自己的时序系统算出来的。3.4 用conntrack命令查看连接级明细深挖单条连接如果你的问题不是“总量多大”而是“哪条连接在跑大流量”那就要进连接跟踪表细看。工具是conntrack安装包一般叫conntrack-tools。# 查看当前所有连接过滤出字节数排序前10 conntrack -L -o extended | awk {print $NF} | sort -rn | head -10conntrack -L输出长格式时每条连接末尾会有bytes... packets...字段。-o extended这个参数很关键它额外输出标记、secmark等扩展信息也确保字节数字段出现在解析里。如果要做每IP聚合conntrack -L -o extended | awk /udp|tcp/ { for(i1;iNF;i) { if($i ~ /^src/) {split($i,a,); srca[2]} if($i ~ /^bytes/) {split($i,b,); bytesb[2]} } total[src]bytes } END {for(ip in total) print total[ip], ip} | sort -rn | head -20这里的坑在于conntrack -L在高连接数的机器上本身就是重操作它会读全部连接表可能占用CPU几十毫秒甚至更多。生产环境大表比如超过十万条连接我是绝对不用它做高频轮询的——只用于事故现场手动排查。3.5 nftables下的统计实现——现代服务器更推荐如果你用的发行版已经全面转向nftables比如新装的Debian 12、Ubuntu 22.04而且没有老iptables套件那么统计写作nftables规则要干净得多。nftables原生支持counter关键字能直接嵌在规则里nft add table inet traffic_stat nft add chain inet traffic_stat count_in { type filter hook input priority 0; } nft add rule inet traffic_stat count_in tcp dport 8080 counter读取时也更方便nft list table inet traffic_stat输出里直接能看到packets 12345 bytes 6789012。nftables的counter天生支持动态map你可以定义一张“IP地址-计数器”的映射表然后一行规则对每个新源IP自动建计数器nft add table inet traffic_stat nft add set inet traffic_stat per_ip { type ipv4_addr; flags dynamic; } nft add rule inet traffic_stat count_in ip saddr per_ip counter之后每来一个不同的源IP集合里会自动增加一条记录并配一个独立的计数器。这功能比iptables的“限制规则条数”思路灵活太多也是我近两年主推的方案。4. 深度解析连接跟踪表为什么会满以及它怎么拖垮流量统计4.1 表满的连锁反应比想象中严重连接跟踪表设计成固定容量的哈希表默认值因发行版而异常见是65536、131072或者262144。当表满时内核无法为新建连接分配跟踪条目于是静默丢包丢弃的位置在netfilter框架的nf_conntrack_in阶段后面你再有防火墙、NAT都没机会执行。结果是外部新请求进不来但Server端已经在跑的ESTABLISHED连接不受影响。这种故障最有迷惑性的特征是“半通”——用户访问部分失败部分成功老连接正常重启服务后短暂恢复又恶化。如果你对这种场景没经验很容易误判成应用层问题反复重启服务浪费时间。4.2 哪些流量会大量消耗连接表条目UDP和TCP短连接是大头。TCP短连接三次握手建一条四次挥手后条目不会立刻消失默认TCP连接的超时时间是432000秒5天——你没看错一条已经关闭的TCP连接conntrack条目最长可以赖在表里5天才被回收。UDP默认超时30秒反而短得多。所以一条TCP连接只要存活超过超时时间或者关闭后没被立即回收就会长期占据一个表项。高并发短连接的服务比如Web API、RPC调用非常容易把表堆满。业界普遍的调优手法是修正超时参数# 缩短TCP连接超时从5天改为1小时 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established3600 # 短连接场景可以进一步改小但要评估业务是否有长连接另外还有两个隐藏消耗一是NAT情况下同一个内网IP的大量连接源端口很快耗尽但如果五元组不同conntrack照样需要独立条目二是有很多“半开连接”的场景SYN Flood攻击会让表里充满SYN_SENT状态的残留条目。4.3 表满之后的流量统计直接就废了这里有个恶性循环值得单独拉出来说。连接跟踪表满后新连接无法被跟踪意味着你通过conntrack日志做流量统计的那些路径天然漏掉了被丢弃的连接流量。表现在你的统计系统上就是流量数字突然掉下去了但实际带宽占用可能还很高。只看统计结果的话你会误以为攻击停了其实只是连接跟踪已经被打瘫了。所以做流量统计必须联动监控连接跟踪表的使用率。表的使用率本身才是这台机器网络健康度的“体温计”。一旦超过80%统计数字的可信度就要打折扣得先处理表满问题再来谈流量分析。5. 实战案例复盘一次连接表告警背后的流量统计排查5.1 现象与初步定位去年我接手一个内网网关的维护某天凌晨告警网关的nf_conntrack_count超过阈值且连续三次采样都在攀升。开始时我没有着急调大nf_conntrack_max因为机器的内存并不紧张盲调大只会掩盖问题——如果真是攻击流量你调再大也会被打满。我的排查顺序先看系统连接跟踪状态里的TCP状态分布cat /proc/net/nf_conntrack | awk -F {print $4} | sort | uniq -c | sort -rn输出的状态里大量集中在SYN_SENT和TIME_WAIT。SYN_SENT偏多说明可能有对外异常连接在积压TIME_WAIT大是正常的但配合连接数持续上涨就不是正常的了。5.2 顺着连接表挖出元凶接着我用conntrack -L过滤出SYN_SENT状态的连接按目的IP聚一下conntrack -L -o extended | grep SYN_SENT | awk -F dst {print $2} | awk {print $1} | sort | uniq -c | sort -rn | head结果一目了然有一个外网IP被大量去连而且都是SYN_SENT——对方根本不回包。netstat -antp确认是某个Java服务在疯狂重试外部接口调用对方接口有问题重试机制没做熔断很快把连接表堆满。这个案例最有价值的经验是先看连接跟踪的状态分布再看异常的远端IP最后回到应用层的重试逻辑。流量统计的表象是“连接数暴涨”但真实凶手是应用层没有保护。我当时把服务的超时时间从3秒改成1秒并且加了熔断连接跟踪表立刻回到正常水位。5.3 事后补上的流量统计方案处理完事故后我给网关加了完整的流量统计与告警体系/proc/sys/net/netfilter/nf_conntrack_count每30秒采集一次超过nf_conntrack_max的75%发P2告警90%发P1。按源IP聚类统计TCP SYN连接速率每5分钟计算一次超过基线十倍以上触发告警。iptables统计链按月保留每天早上把前一天的累计字节和包数推到表格存储供业务方按IP查月度用量。这套体系上线之后同样的问题再次出现时监控能在我还没被用户投诉之前就发出告警。6. 常见问题速查与避坑经验6.1 为什么计数器统计的流量和实际带宽对不上这件事最容易引起业务方质疑。首先要搞清楚iptables计数器统计的是“经过这台主机网络栈处理的IP层流量”不含以太网帧头、不含交换机层面的广播流量也不含被DPDK这种用户态驱动绕过的数据包。如果你的机器上有部分流量走XDP/DPDK旁路了那计数器天生就统计不到。另外本机回环流量lo口算不算你的业务流量取决于你规则链挂的位置。我做统计时通常会把lo接口排除在外避免重复计数。6.2 conntrack日志丢失统计出现空洞用conntrack日志方案时事件通过netlink socket传递给用户态如果用户态程序处理不过来内核socket缓冲区满了就会丢弃消息。这种丢弃是静默的日志里看不出异常只会表现为某段时间的连接事件缺失。解决思路一是加大接收缓冲区net.core.rmem_default二是做降级——如果事件吞吐量过大就不追求逐条记录改为周期性全量快照的增量式统计牺牲实时性换完整性三是把连接表Dump快照定期落盘比如每5分钟把/proc/net/nf_conntrack导出压缩存一份事故后直接翻历史快照就行。6.3 计数器反向增长数据出现气泡我踩过一次很典型的坑。写统计脚本时拿iptables计数器差值计算速率结果符号写反了还是其次问题是计数器在某个时间点突然跳变到超大值。查原因发现是有人手动清空了规则重新加载后计数器归零然后脚本认为是“反向回绕”算出来的速率变成了天量数字。这个问题的鲁棒解法是脚本里判定如果当前计数比上次小就丢弃这一轮差值一律输出0而不是输出负数。同时规则文件的变更操作要规范走自动化发布避免人工干预计数器。6.4 如何应对Kubernetes节点上的连接跟踪统计盲区Kubernetes节点上Kube-proxy的iptables或IPVS模式大量依赖连接跟踪。特别是IPVS模式它本身有更多连接条目因为每个Service的每个后端组合都会占据独立的连接跟踪项。流量统计的难点在于Service的ClusterIP只是虚拟IP你按源IP分类能聚合按目标Service归类就有难度了。我的建议是K8s场景下连接跟踪统计尽量按Pod所在节点和网段聚合配合Service Mesh的sidecar流量指标综合判断。纯靠conntrack做细粒度业务流量拆解不仅效率低而且容易误判。7. 终点之前留几句实用闲话最后说点不写在教科书里的感受。连接跟踪流量统计这个技术点不像高并发框架那样能带来炫酷的架构升级也出不了什么精彩的PPT但在真实的生产环境里它就是我这种人赖以为生的“底层能力”。说实话我自己最初踩的坑很多都不是技术难题而是没把“连接跟踪表也是要监控的”这件事当回事。给主机加内存、加CPU、加带宽都不如提前把nf_conntrack_count盯牢来得实在。还有一个心得是统计不是为了做日报而是为了发现“异常”。一个稳定运行的系统连接数、字节数、包数在时间轴上应该是平滑的。任何突兀的抖动都值得你去连接跟踪表里翻一翻。与其研究更花哨的流量分析平台不如先把自己的计数器脚本和告警阈值搞好。如果你现在手头正好管着几台NAT网关或K8s节点建议今天就跑一遍cat /proc/net/nf_conntrack | wc -l cat /proc/sys/net/netfilter/nf_conntrack_max先把这两个数记下来再顺手看一眼你的监控系统里有没有这两个指标。没有的话补上它们比任何花架子优化都实在。
阅读完成 · 觉得有帮助?