最近被问得最多的一个问题:nftables 到底比 iptables 快在哪?有没有实测数据能参考?老实说,网上聊 nftables 的文章不少,但大部分停留在“新框架、效率高”这种感性描述上,真正给出可复现测试方案和趋势结论的很少。正好我这半年一直在把线上防火墙往 nftables 迁,也做了几轮对比测试,今天就把性能优势的来源、压测思路和几组参考数据一次讲清楚。
先说结论:nftables 的性能不是靠某个“魔法开关”,而是靠执行模型和数据结构的重构。它把防火墙规则集从一条条“链表记录”变成一份“可编译、可索引的规则程序”,再配合内核里哈希表、红黑树等结构做大集合匹配。这套设计在规则少时和 iptables 拉不开差距,规则一多、更新一频繁,差距就非常明显。适合谁看?正在规划从 iptables 迁移的网络工程师、被多规则场景性能折腾过的安全运维,还有想在生产环境验证“别人说 nft 快”的 Linux 玩家。
1. nftables 性能优势的本质:从“遍历链表”到“可编译的规则集”
1.1 iptables 的执行模型与真正的瓶颈
iptables 是 netfilter 框架的老牌用户态工具,内核里每个表(filter、nat、mangle、raw)都由若干条链组成,每条链本质上是线性链表。数据包进入 hook 点后,从链头开始逐条匹配,直到第一条命中的规则产生动作(drop、accept、jump 到自定义链等)。
这个模型在规则量少的时候完全够用,几十条规则,平均匹配几次就结束了,CPU 开销可以忽略。但规则一旦堆到几百上千条,流量又大(尤其是 64 字节小包场景),问题就来了:每个包都要从链头重新走一遍规则,平均匹配次数随着规则数量线性上涨,CPU 大量消耗在 ruleset 遍历和分支预测失败上。
更麻烦的是 iptables 的多表穿行。一个包在转发路径上,raw、mangle、nat、filter 都可能被分别检查,自定义链之间还要跳转(jump/goto)。规则放的位置稍不注意,平均查找路径就会被拉长。你可以把 iptables 想象成一条长走廊,保安从 1 号房间开始一间一间查,直到找着对应的门牌。平时人少无所谓,但 DDoS 流量像马拉松一样涌进来时,保安直接在走廊上跑死。
1.2 nftables 的设计:规则集即程序
nftables 从设计之初就走了一条不同的路:把链、规则、表达式整体编译成内核可执行对象。它不再要求每条规则都从链表头开始,而是允许你把匹配条件结构化——能用集合(set)用集合,能用映射(map)用映射,内核里的哈希表或红黑树来做查找,复杂度接近 O(1)。
即便你不用集合和映射,nftables 的规则执行路径也比 iptables 更紧凑。规则内部采用表达式组合,verdict(跳转/接受/丢弃)处理的指令密度比“逐条 iptables 规则”要精炼,一个包在规则集里经过的条件判断次数更少。再加上 nftables 是单一框架,IPv4、IPv6、ARP、bridge 共用一套内部结构,而不是像 iptables 那样每个协议族维护一套独立的表,存储和更新的开销也低一截。
提示:很多人误以为“nftables 快是因为 netfilter 框架本身变了”,其实 netfilter hook 体系还在,conntrack 也还是那个 conntrack。真正的变化在规则集的数据组织和查找方式。
2. 五个最能体现 nftables 性能优势的场景
2.1 大中型规则集:从线性搜索到哈希查找
这是 nftables 和 iptables 差距最直观的场景。生产环境里,出口防火墙上千条黑名单、IDC 安全网关做正则式源 IP/端口过滤,这些都不罕见。iptables 在这种规则量下,每新增一条规则,所有新连接的平均匹配成本都会增加一点。
nftables 的大集合查找几乎是“一条规则”完成判断。比如动态封禁一批 IP:
nft add table inet myfilter nft add set inet myfilter blacklist { type ipv4_addr\; flags timeout\; timeout 1h\; } nft add element inet myfilter blacklist { 1.2.3.4, 5.6.7.8 } nft insert rule inet myfilter forward ip saddr @blacklist drop上面这条规则的意思是:只要源 IP 落在@blacklist集合里,直接 drop。后续加 IP 只需要nft add element,数据面查找走哈希表,不用改动规则本身。我线上压测的感觉是,规则量超过 500 条以后,iptables 的 PPS 下降趋势已经肉眼可见;到了 3000 条以上,同等规则语义下 nftables 的包处理能力能高出 iptables 好几倍,规则量越大优势越明显。
2.2 动态更新与批量事务:从“抖动窗口”到“原子生效”
生产防火墙最怕的不是规则多,而是改规则的那一瞬间。老运维应该都经历过:用 iptables 逐条-A添加规则时,要么先 flush 整条链再重灌,要么一条一条往上加,中间要么出现短暂无保护窗口,要么出现规则集半更新状态。对安全设备来说,这个窗口是致命的。
nftables 支持事务式提交,所有规则变更可以放到一个文件或一次 netlink 消息里,要么全部生效,要么全部回滚。例如:
cat /etc/nftables.update.conf add element inet fw blocked { 203.0.113.5 } delete element inet fw blocked { 198.51.100.2 } nft -f /etc/nftables.update.conf我实测过动态封禁/解封场景:批量更新 5 万条黑名单元素时,iptables 逐条执行要好几分钟,期间 CPU 持续走高;nftables 用事务式文件提交,几秒内完成,数据面没有出现明显丢包和抖动。iptables-restore 虽然能缓解一部分问题,但它本质上是先清空再导入,仍然存在原子性缺口和回滚缺失。对依赖 API 自动化下发的安全平台来说,这个差距直接决定了可用性。
2.3 集合与映射:一条规则替代一百条规则
iptables 里很多场景需要展开成多条规则:不同 IP 走不同动作、不同端口段做不同策略、黑白名单混合……规则越多,链越长,性能越差。nftables 的映射(map)机制可以把“判断”变成“查表”。
举个例子,按目的 IP 走不同策略:
nft add table ip fw nft add chain ip fw forward { type filter hook forward priority 0\; } nft add map ip fw policy { type ipv4_addr : verdict\; } nft add element ip fw policy { 192.0.2.10 : drop, 198.51.100.0/24 : accept } nft add rule ip fw forward ip daddr vmap @policy这里vmap @policy的意思是:拿目的 IP 去查 verdict map,查到谁就直接执行对应的动作。该拒绝的拒绝,该放行的放行,全部在哈希表里完成,不再逐条比对。我见过有人把几百条 iptables 白名单策略用一张 nftables map 重写,规则文件从几百行缩到几十行,线上 CPU 占用反而降了。这就是“少规则、高信息密度”带来的缓存友好性——规则集越小,CPU cache 命中率越高,包处理越快。
2.4 多核与软中断协同
防火墙吃 CPU,主要不是吃在规则引擎本身,而是吃在软中断收包、conntrack 哈希表查询和规则匹配三件事上。前两件事 iptables 和 nftables 都要做,差异不大;区别在规则匹配路径。
iptables 的规则更新会引入全局锁串行化,尤其在频繁增删规则时,多个 CPU 核心会互相等待。nftables 的规则集在数据面以只读方式被各核心共享,更新走事务机制,匹配路径上的锁开销更小。配合网卡多队列、RSS(Receive Side Scaling)、IRQ affinity 设置,每个核心独立处理自己的队列,扩展性明显更好。
我在双路服务器上做过并发压测:多个线程同时往防火墙里灌规则,iptables 偶发 CPU 飙升和软中断不平衡,nftables 的表现要平滑得多。多核场景下,nftables 的吞吐扩展曲线更接近线性,iptables 则容易出现平台期。
2.5 与 conntrack/NAT/限速组合的复合场景
现实中的防火墙不会只有过滤规则,还有状态跟踪、NAT 映射、限速、日志。iptables 做全套策略,经常要在 raw、mangle、nat、filter 多张表里来回穿行,一个连接被检查很多次。nftables 可以把状态判断和地址/方向判断组织在同一个链里,结构化完成。
比如一个比较完整的 forward 链,需要判断连接状态、匹配源地址集合、执行 NAT 映射、决定最终动作,用 nftables 可以在同一条链内按优先级组织不同表达式,减少多次跳转带来的额外开销。这也是很多人提到“防火墙关闭有影响吗”时容易忽略的点:很多时候瓶颈根本不在规则引擎,而在 conntrack 表满和软中断压力上,关闭防火墙不但不解决问题,还白白丢掉安全防护。
3. 实测数据参考:一套可复现的 nftables vs iptables 对比方案
3.1 测试环境怎么搭
网上流传的“nftables 比 iptables 快几倍”大多没有交代环境和规则集设计,参考价值有限。我自己做对比测试时,环境是这样搭的:
| 项目 | 配置 |
|---|---|
| CPU | Intel Xeon E-2278G 8C16T,隔离 4 个核给软中断 |
| 内存 | 32GB |
| 网卡 | Intel X710-DA2 双口 10GbE,开启多队列 |
| 内核 | 6.1 LTS,nf_tables 模块默认开启 |
| 发包工具 | TRex / pktgen,固定 64 字节小包 |
| 流量模型 | 随机目的端口/随机目的 IP,模拟五元组差异 |
关键点:对比必须在同一台机器、同一个内核版本下进行,否则内核参数差异会污染结果。建议先把 iptables 的规则集准备好,用iptables-restore一次性挂载测试一轮;再把这套规则等价翻译成 nftables 原生语法,用nft -f挂载测试另一轮。
3.2 规则集怎么设计才公平
公平对比的核心是“规则语义等价”。我建议分三档规则量:10 条、1000 条、10000 条。规则内容统一为五元组匹配(源 IP、目的 IP、协议、源端口、目的端口),最后一个匹配规则写 drop,这样每个包都要走到链尾附近,能充分暴露查找路径长度差异。
注意,公平对比不应该让 iptables 使用 ipset。ipset 是独立于 iptables 的扩展工具,虽然它也用哈希集合,但它不代表 iptables 原生规则集性能。我们要对比的是“两者作为防火墙框架本身的规则集组织能力”。如果你的 iptables 命令实际指向的是 iptables-nft 兼容层,那它本质上已经在用 nf_tables 后端了,但因为你写的是 iptables 语法,享受不到原生 set/map 的数据结构优势,性能也会打折。这个后面细说。
3.3 我看过的实测数据和自己的样本
公开资料里,Open vSwitch 社区、Red Hat 博客和一些海外网络工程博客都发布过 nftables 与 iptables 的基准测试,可以用 “nf_tables iptables benchmark” 这类关键词搜到。大家的方向性结论高度一致,我这里也给出自己测试机上的一组趋势数据:
| 场景 | iptables | nftables | 说明 |
|---|---|---|---|
| 10 条规则,64B 小包 | 接近网卡上限 | 接近网卡上限 | 规则集短时线性遍历不构成瓶颈 |
| 1000 条规则,64B 小包 | 明显下降,CPU 成瓶颈 | 下降幅度小,接近线速 | 集合/映射查找优势充分体现 |
| 10000 条规则,64B 小包 | 断崖式下跌 | 仍可维持可用水平 | 差距可达一个数量级 |
| 50000 条规则热替换 | 逐条添加需分钟级 | 事务式提交秒级内完成 | 动态更新场景差异最大 |
强调一下:上面这些数字只代表我所在测试机的趋势,不要直接拿去当基准。硬件、内核、规则内容不同,绝对 PPS 会差很多。但方向性结论是稳定成立的:规则量越大,nftables 的查找优势越明显;更新越频繁,nftables 的事务优势越突出;大包场景两者都能线速时,差异反而不重要。
3.4 为什么小包测试最考验防火墙
64 字节小包是网络设备的“照妖镜”。小包意味着单位时间里包的个数更多,规则匹配次数更多,CPU 成为瓶颈。1518 字节大包更容易打到线速,因为每个包承载的数据量大,CPU 有更多时间去查规则。很多人看到“防火墙跑满万兆”就觉得性能没问题,实际上可能只是他的业务流量是大包为主。真正要评估防火墙极限,必须用小包测试。
另一个容易被忽略的指标是“规则更新耗时”和“更新期间是否丢包”。我用脚本循环执行封禁/解封 IP 时,iptables 版本偶尔会出现规则集半更新状态,CPU 使用率明显波动;nftables 版本用事务批量提交,数据面平滑无丢包。这个体感差异比单纯看 PPS 更关键——生产环境里,防火墙规则更新频率高不高,直接影响业务可用性。
4. 迁移与调优:把 nftables 的性能吃透的实操要点
4.1 先分清原生 nftables 与 iptables-nft 兼容层
很多发行版默认的iptables命令已经指向 iptables-nft 兼容层,只是把 iptables 语法翻译成 nf_tables 后端执行。执行iptables -V,如果输出带nf_tables字样,那说明你已经在用 nf_tables 内核框架了。
但兼容层为了保持 iptables 语义,只能沿用“逐条规则、线性链”的表达方式,用不上原生 nftables 的 set、map、vmap、事务式批量提交这些关键武器。你要测 nftables 的真实性能,或者想在线上享受 nftables 的红利,就得写原生 nft 语法,用nft命令直接操作。兼容层只能作为迁移过渡,不能当性能解。
4.2 集合与映射的类型选型决定生死
nftables 的 set 不是只有一种实现。类型声明会直接影响数据面查找效率和内存占用:
- 默认集合对小规模固定元素表现很好。
flags interval用于 CIDR 聚合,内核用区间树存储,适合“10.0.0.0/8、192.168.0.0/16”这类大量网段合并的场景。flags timeout用于动态过期元素,适合封禁名单。dynamic与timeout配合,可以做到“首次见包自动加入集合并计时”,相当于用户态 CT 自动封禁的基础。
我在生产里踩过的坑是:把所有 IP 都丢进一个没声明类型的大集合,某些特定查找模式会退化。正确做法是,先想清楚集合的访问模式——是固定黑名单,还是频繁增删的临时封禁,还是网段聚合,然后选对应 flags。选错了,性能可能还不如 iptables。
4.3 链的层次与优先级设计
nftables 的链既可以挂到 netfilter 标准 hook(prerouting、input、forward、output、postrouting),也可以做普通链供其他规则跳转。每个挂 hook 的链都有 priority 数字,数字越小越先执行。比如 conntrack 相关处理通常在那里,filter 链默认 priority 0。
实操建议:不要为了“结构清晰”搞太多普通链跳来跳去,每次 jump 都有额外开销。能用集合、映射在一个判断里解决问题的,就不要拆成两层链。尤其避免“filter 链跳自定义链、自定义链里再跳另一个自定义链”的三层跳转结构。规则集确实需要分文件分表管理,但运行时执行路径要尽量扁平。
4.4 内核参数和网卡队列的配合不能少
nftables 再快,也快不过网卡收包瓶颈。测试和生产环境都先确认网卡多队列打开没有:
ethtool -l eth0 ethtool -L eth0 combined 8配合 RSS 让不同队列把不同五元组哈希到不同 CPU,软中断就能并行处理。还可以检查nf_conntrack_max和nf_conntrack_buckets,conntrack 哈希表太小会导致连接追踪成为瓶颈,表现就是“防火墙规则看似不多,但 CPU 全在 softirq 里打转”。很多人以为关掉防火墙能提升性能,实际排查下来往往发现是 conntrack 表满,或者网卡队列没开。先调这些,比关防火墙靠谱得多。
4.5 规则集管理上的性能卫生
日常运维里,nft list ruleset在规则很多时是个昂贵的操作,全量输出全套规则并格式化,几百条还好,几万条的时候会明显吃掉 CPU。生产环境不要在高流量时段反复执行全量 list,需要看规则就按表按链过滤查询。
批量更新前先做语法检查:
nft -c -f /etc/nftables.conf-c是 check 模式,只检查不提交,能在真正生效前发现语法或引用错误,避免事务提交到一半失败触发的回滚流程。这个习惯和我前面说的事务机制配合起来,线上规则变更的风险能低很多。
5. 常见问题与排查技巧实录
5.1 问题速查表
| 现象 | 大概率原因 | 快速定位方法 |
|---|---|---|
| nftables 性能没比 iptables 好多少 | 用了 iptables-nft 兼容层 / 没用到 set 和 map / 规则本身就几条 | iptables -V看后端,检查规则集结构 |
| 动态封禁后 CPU 持续走高 | set 没声明 timeout,元素只增不减 | nft list set查看集合元素数量,确认 flags |
| 规则集很大但查询依然慢 | 集合类型选错,比如固定 IP 段应走 interval | 查看 set 定义,按访问模式重选 flags |
| 防火墙规则改动期间丢包 | 还在用逐条增删方式,没用事务 | 改用nft -f批量提交,或把多条命令写入一个事务 |
| 小包流量 CPU 满载、大包正常 | 规则匹配是瓶颈,需要看规则集规模和结构 | 用小包压测,逐条检查规则平均匹配路径 |
| 多核扩展性不好 | 网卡未开多队列,或软中断绑核不合理 | ethtool -l和/proc/irq/核对 |
5.2 我踩过/见过的几个坑
第一个坑:在旧内核上用新特性。nftables 基础功能内核 3.13 就有了,但 set、map 的高级特性、interval 集合、带 timeout 的动态集合,依赖的内核版本更高。我见过有人把生产环境内核停在 4.x,然后上了flags interval的集合,触发奇怪的性能问题。先查内核版本和发行版 nftables 版本再选特性。
第二个坑:动态集合的 timeout 和垃圾回收间隔。flags timeout的集合支持元素自动过期,但 GC 运行有间隔,如果你频繁加元素又不清理,集合会在短时间内膨胀,哈希表负载升高,查询变慢。合理的做法是设置合理的 timeout,并定期手动清理不再需要的元素区块。
第三个坑:把“能用一条 map 解决的事写成几百条规则”。这个坑更多来自习惯——从 iptables 迁过来的人,第一反应还是“一个动作一条规则”。nftables 的 map/vmap 机制其实更像路由表,按 key 查结果。你越早习惯用“查表”思路写规则,越能体会到性能红利。写每条规则前都先问一句:这个判断条件能不能塞进集合或映射?
5.3 从老框架迁移的一个实用技巧
迁移时别一次性从 iptables 全量重写规则。建议先梳理线上规则,给每条 iptables 规则标注“用途”和“命中率”,然后把高命中率、高频检查的规则优先迁到 nftables 的 set/map 结构里。低频规则可以暂时留在兼容层里过渡。这样既控制风险,又能把 nftables 的收益用在刀刃上。迁移完成后,再用nft list ruleset和之前的 iptables 规则做差异核对,确认语义一致。
我在实际运维中的体会是,nftables 真正改变的不只是性能数字,而是心态。以前改防火墙规则像在做高风险外科手术,现在事务式提交加自动回滚,规则变更变成了日常操作。最后再分享一个小技巧:如果你要频繁检查某条规则是否生效,别用nft list ruleset | grep,直接nft get element查集合里的具体元素,代价小一个量级。这是我最近用下来体验最明显的一个细节。