Hash 的工程优势: port range 匹配

昨天和朋友聊到 “如何匹配一个 port range”,觉得挺有意思,简单写篇散文。

回想起十多年前,我移植并优化了 nf-HiPAC,当时还看不上 ipset hash,后来大约七八年前,我又舔 nftables,因为用它可直接写多维树匹配,更早之前,Linux 内核 Hash 路由查找算法被 trie 替代时,我就写文捧过一番,我是有多么看不上 Hash,似乎任何一棵 Tree 都吊打 hash。

多年以后反思,如果再让我做同样的需求,我定会 Hash 做到底,不会再动 Tree 的主意。Hash 实现最简单,并可随内存线性扩展,在大多数场景下也不会比 Tree 差,只有纯理工科背景且未被工程教训毒打过的副经理才会拎出 Tree 更好的例外作为替换 Hash 的理由。

匹配 port range,想当然的算法是构建区间查找树,当年看 Linux 内核 mmap 实现时看到过 Linux 文件映射就是用区间树实现,所以但凡和区间关联的,我都会去安利区间树,也因此当年优化 nf-HiPAC 时也就是选定了它,但在实现过程中遇到了极大的困难,于是我就偷了个懒。

有意思的是,这个偷懒很值得。

我没有用实际 rule 中的 port range 直接构建区间树,而将整个 port 空间分为一致 500 个端口一组的等距区间,然后将实际 rule 的 port range 往上盖,在等距边界处做 split。比如 rule 的 range 1234~1400,则 1000~1500 等距区间就被分为了 3 部分,这 3 部分作为匹配 1000~1500 后的二级匹配,执行一个线性遍历就完了。

我当时非常看不起线性遍历,所以一直耿耿于怀,我当时不知道,几十以内的线性遍历其实是无伤遍历,更何况个位数。巧的是我当时能力不足以让我继续优化成 Tree,就保留了 “二分等距区间查找 + 线性遍历” 的 “拙劣” 实现,没想到它工作得非常好。

回想起来,这种等距区间分割,让规则中的 port range 适配它的做法,依然属于横竖颠倒,拨云见日。我对这种方法论的掌握已经深入了内心,下意识而为之。

现如今,我连等距区间树也要扔掉,用 hash 替代等距区间树,就是另一个新的算法:
在这里插入图片描述
Hash 相比树的缺点在于要遍历冲突链表,比如 Linux 内核里的 hlist。假设 hash 算法足够优秀(没得说,都不差),hlist 中元素的个数是可随着内存增加减小的,而树的操作无论多好的 CPU 始终是 log 级。

虽然 Hash 要额外处理冲突,但树也不是一步到位的,加上树的平衡,锁等复杂操作,在通用软件场景下,其性价比远小于 Hash。假设 50000 并发,2000 个 hash bucket,平均只需要遍历 25 次,而采用二叉树需要 15 次操作,但算上其插入,平衡操作,是要比 hash 更昂贵的。二叉树只在更大并发时才凸显优势,其操作量随数据量 log 增长,而线性增长的 hash 操作亦可通过增加内存抵消操作数量。但如若真遇到海量并发,通用软件本身就成了瓶颈。

确保下面的区域:
在这里插入图片描述
显然,x 会随内存增加向右线性延展,,而 log 曲线 y = α ⋅ log ⁡ 2 x y=\alpha\cdot\log_2{x} y=αlog2x 则会因 CPU 性能提升而下压。纯算法分析,log 下压更明显,但纯算法分析,Hash 简直就是 O(1),所以二者并非简单的时间空间较劲二选一,而是呼吁架构的改变。

其实说白了就是 Hash 简单易实现没 bug,特别是频繁增删查的场景,一个反面案例来自 David Miller 对 IPv6 路由查找的 “优化”,惹了不少麻烦(详见 3.10 内核中 IPv6 的缺陷),要是用 Hash 实现,不可能有这事。

说点形而上。

Hash 和 Tree 实际上代表了计算在空间和时间分别展开的两个方向,Hash 的 O(1) 约束下,1 倍的规模增量可带来1 次操作增量,需要 1 倍的内存来抵消这 1 次的操作以维持 O(1),操作时间不变,对于二叉树,1 倍的规模增量同样带来 1 次操作增量(每增加 1 层,叶子节点数量增加 1 倍),但这次操作无法抵消,时间永远随规模增加而单调递增,然而由于二叉树在操作过程中天然保序,就意味着其不真需要额外预留 1 倍空间以支撑规模。

时间不可压缩,但空间可压缩,这是时空的本质不同,接受一个随规模递增得慢的时间,去压缩空间,这是所有机器的实现方式。背后是一个选择问题,我们是选择在时间中等待,去压缩空间,还是选择线性扩展空间,只为不等待,还是那个 “矩” 的长宽权衡。

直白说,空间不可无限扩展,我们倾向于压缩它,我们设计的机器也是,而时间总是流逝不可压缩,我们倾向于高效利用它,我们设计的机器也是。物件越来越多时,我们倾向于将它们分类叠放以便查找而不是在更大的空间平摊以便一眼瞅,空间的扩张总有极限,而时间却无限延展。空间是共享的,我们的一生时间却是私人的。

但我们还是希望有套稍微大一点哪怕极简的房子,在多数场景,它比紧凑的装修和储物分类更简单,更令人舒适,这还不够的话,就看看我们智人的历史,看看我们作为自己是如何学会 “集约(字面意思)” 的,我们的所谓文明,就是这种方式,所以我们设计的机器也是这种方式,但在大多数时间,我们却是用相反的方式:
在这里插入图片描述

首先要地盘,其次不要太大,这就是选择 hash 的理由。

浙江温州皮鞋湿,下雨进水不会胖。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/81892.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka学习笔记(三、消费者Consumer使用教程——使用实例及及核心流程源码讲解)

1.核心概念与架构 1.1.消费者与消费者组 Kafka消费者是订阅主题(Topic)并拉取消息的客户端实例,其核心逻辑通过KafkaConsumer类实现。消费者组(Consumer Group)是由多个逻辑关联的消费者组成的集合。 核心规则 同一…

《java创世手记》---java基础篇(下)

《Java 创世手记 - 基础篇(下)》 第五章:契约与规范 —— 接口 (Interfaces) 与抽象类 (Abstract Classes) 造物主,在你日益繁荣的世界里,你发现仅仅依靠“继承”来构建“物种体系”有时会遇到一些限制。比如&#x…

气镇阀是什么?

01、阀门介绍: 油封机械真空泵的压缩室上开一小孔,并装上调节阀,当打开阀并调节入气量,转子转到某一位置,空气就通过此孔掺入压缩室以降低压缩比,从而使大部分蒸汽不致凝结而和掺入的气体一起被排除泵外起此…

计算机一次取数过程分析

计算机一次取数过程分析 1 取址过程 CPU由运算器和控制器组成,其中控制器中的程序计数器(PC)保存的是下一条指令的虚拟地址,经过内存管理单元(MMU),将虚拟地址转换为物理地址,之后交给主存地址寄存器(MAR),从主存中取…

从equals思考对“正念”的认知

正念 很多人聊正念,每个人有自己的解说,我听到最符合逻辑的一个说法:正念就是对抗惯性。 如果尝试过打坐或者冥想,就有一个说法叫正观,什么意义呢?就是说感受自己的呼吸,自己的心跳&#xff0c…

信息安全管理与评估2025山东卷

需要其他赛题解析的可联系博主

【leetcode】02.07. 链表相交

链表相交 题目代码1. 计算两个链表的长度2. 双指针 题目 02.07. 链表相交 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。 图示两个链表在节点 c1 开始相交: 代码 …

可视化与动画:构建沉浸式Vue应用的进阶实践

在现代Web应用中&#xff0c;高性能可视化和流畅动画已成为提升用户体验的核心要素。本节将深入探索Vue生态中的可视化与动画技术&#xff0c;分享专业级解决方案与最佳实践。 一、 Canvas高性能渲染体系 01、Konva.js流程图引擎深度优化 <template><div class"…

⼤模型驱动的DeepInsight Copilot在蚂蚁的技术实践

本文整理自潘兰天&#xff08;蚂蚁数据智能团队数据分析平台技术专家)在DA数智大会2025上海站的演讲实录。 本文围绕AI技术在数据分析领域的应用及DeepInsight Copilot产品展开。DeepInsight是一款蚂蚁长期深耕数据分析领域的BI产品&#xff0c;本文首先介绍了DeepInsight Copi…

Express教程【003】:Express获取查询参数

文章目录 3、获取URL中携带的查询参数3.1 参数形式&#xff1a;查询字符串3.2 参数形式&#xff1a;动态参数3.3 参数形式&#xff1a;Json数据 3、获取URL中携带的查询参数 3.1 参数形式&#xff1a;查询字符串 1️⃣通过req.query对象&#xff0c;可以访问到客户端通过查询…

在CentOS7上使用tree查看目录树

文章目录 1. 利用yum安装tree2. 利用rpm安装tree2.1 下载tree的rpm包2.2 上传到云主机2.3 安装tree软件 3. 使用tree查看目录树4. 实战小结 1. 利用yum安装tree 执行命令&#xff1a;yum -y install tree CentOS7停止更新&#xff0c;即使更新镜像源&#xff0c;也无法正常安装…

大规模JSON反序列化性能优化实战:Jackson vs FastJSON深度对比与定制化改造

背景&#xff1a;500KB JSON处理的性能挑战 在当今互联网复杂业务场景中&#xff0c;处理500KB以上的JSON数据已成为常态。 常规反序列化方案在CPU占用&#xff08;超30%&#xff09;和内存峰值&#xff08;超原始数据3-5倍&#xff09;方面表现堪忧。 本文通过Jackson与Fas…

华为交换机S12708常用命令

以下是华为S12708交换机&#xff08;高端园区/数据中心核心交换机&#xff09;的常用运维命令&#xff0c;涵盖基础配置、状态查看、故障排查等场景&#xff1a; 一、基础配置命令 1. 系统管理 system-view # 进入系统视图 sysname S12708-Core # 设置设备名称 clock timez…

通过海康萤石API控制家里相机的云台及抓图

通过海康萤石API控制家里相机的云台及抓图 一、背景二、环境准备2.1 注册开发者账号2.2 安装依赖库2.3 创建`.`env`文件三、代码片段解释3.1 加载并使用环境变量3.2 发送HTTP请求的封装函数3.3 获取AccessToken3.4 分页查询设备列表3.5 抓拍图片3.6 开始云台控制3.7 控制云台并…

XCUITest 是什么

XCUITest&#xff08;全称 Xcode UI Test&#xff09;是苹果官方提供的 iOS/macOS UI 自动化测试框架&#xff0c;集成在 Xcode 开发工具中&#xff0c;专门用于测试 Swift/Objective-C 开发的应用程序。 1. XCUITest 的核心特点 ✅ 官方支持&#xff1a;苹果原生框架&#xf…

mapbox高阶,PMTiles介绍,MBTiles、PMTiles对比,加载PMTiles文件

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️Fill面图层样式1.4 ☘️PMTiles介绍1.5…

5.0以上版本antv/g6使用心得

1. 画布只重新渲染数据 graph.render graph.drawgraph,fitview()graph.fitCenter()setData塞入新的数据 const updateGraph (data) > {if (!graph) {console.warn("Graph is not initialized");return;}graph.clear();graph.setData(data);graph.render(); };…

4.5V~100V, 3.8A 峰值电流限, 非同步, 降压转换器,LA1823完美替换MP9487方案

一&#xff1a;综述 LA1823 是一款易用的非同步&#xff0c;降压转换器。 该模块集成了 500mΩ 低导通阻抗的高侧 MOSFET。LA1823 使用 COT 控制技术。此种控制方式有利于快速动态响应,同时简化了反馈环路的设计。LA1823 可以提供最大 2A 的持续负载电流。LA1823有150kHz/240kH…

如何定位并优化慢 SQL?

如何定位并优化慢 SQL? 一、慢 SQL 的定义与影响 1.1 什么是慢 SQL? 慢 SQL是指执行时间超过预期阈值的SQL语句,通常由以下特征: 执行时间超过慢查询阈值(如MySQL默认10秒)消耗大量CPU/IO资源导致连接堆积或系统负载升高关键结论:慢SQL是数据库性能瓶颈的主要诱因,可…

提升WSL中Ubuntu编译速度的完整指南

在 WSL&#xff08;Windows Subsystem for Linux&#xff09;中使用 make 编译项目时&#xff0c;如果发现编译速度非常慢&#xff0c;通常是由以下几个原因导致的。以下是一些常见的排查和优化方法&#xff1a; &#x1f50d; 一、常见原因及解决方案 ✅ 1. 文件系统性能问题…