千万别!

非常多人这样说,也包括我。

Linux内核早就把HASH路由表去掉了。如今就仅仅剩下TRIE了,只是我还是希望就这两种数据结构展开一些形而上的讨论。

1.hash和trie/radix

hash和tire事实上是能够统一在一起的。具有同样hash值的多个项具有一个共同的特征,这个特征怎么提取呢?无疑这就是hash函数的工作。而trie树(或者radix树,管它呢)的一棵子树也有共同的特征,这个特征怎么提取呢?无疑这就是该子树根节点的父节点指示的某些bits在这棵子树的每个节点都具有同样的值。

实际上,trie树就是hash的一种特殊形式,其hash函数为:取某些bits

trie_hash(value, level)
{return value & level.bits;
}

那么。这么看来,子树的全部节点都应处在一个“冲突链表”里面了...trie树的做法就是“再次hash”,hash函数随之改变。变成取level.bits更低的某些bits了。如此看来。hash路由表解决海量路由项情况下冲突链表变长的方案就是再次hash了,hash函数变成什么呢?我们后面再谈。

2.TCAM的hash

TCAM在非常多地方被用到,它用来依据内容查索引,常被用于路由查询。CPU Cache查询等,以CPU Cache为例。输入TCAM的内容就是一个内存地址,而输出的结果是一个索引。cache匹配的过程就是取到索引指示的cache line,然后比較输入内容(地址)和该cache line指示的地址是否一致。一致就是命中。
       那么TCAM中最核心的过程就是依据地址得到索引的过程,一般的做法就是hash,由于硬连线实现,hash函数绝对不能有太多的计算。因此一般的做法就是“取地址某些bits”,比方取4到7位一共4位,将一个32位(32位系统,物理地址索引cache为例为例)的慢速物理内存地址映射到4位高速cache索引。形成一个金字塔存储结构。32位到4位的映射,丢失了的28位会形成非常大可能性的冲突,而这个就是时间局部性和空间局部性来尽力弥补了,了解列维飞行的应该知道局部性的伟大含义,它构建了我们整个人类文明。
       最简单的hash函数就是取模,实际上也是“取某些bits”,它更加特殊,它是“取最低N bits"。

3.hash和trie树的统一

trie树实际上是从高位到低位逐步hash的过程构建的,其hash函数就是”取某些bits“。

4.查字典的样例-查英文和查汉字

我们小学的时候查字典一般分为音序查法和部首查法,它就形象能体现hash和trie的不同。

为了简便,我以英文单词查法和汉字部首查法为例。
       英文单词是严格一维度顺序排列的,且仅有26个字母组成。因此它能够依照trie树的方式查询,比方what。who,where,前两个字符都是wh,因此说它们具有这么一个共同特征。假设将取这个共同特征作为hash函数,那么在aaa。cc,sahidad。fwfwew,what,qwert,azsx,who。eee,ooo,where中查询who,what。who,where将形成冲突链表,可是一步运算大大降低了匹配的数量,从11个减为3个,然后再进一步hash,依照字母顺序可知at,wre。o这个顺序,直接取第三个孩子节点。因此英语词典的查询方式非常简便。就是一个不断hash定位的过程。hash函数就是”取某些连续字符“。
       我们再看看汉字部首查询法。它是一个典型的计算型hash函数的不断hash的过程。比方在杨。林,棵,马,牛,猪,过。皮这几个字中查”林“字,由于汉字不是一维结构而是二维结构。它的构成是笔画。不是排序的,因此”取某些字符“的方式全然失效(从哪个方向開始取?...怎么算一个字符?...),因此就须要又一次构造hash函数了。长期的历史形成的汉子具有某种象形的意义。通过观察。我们发现”木“字旁是一个特征,这个计算过程,也就是hash函数运行过程是我们的大脑来完毕的。假设说”取某些字符“更加适用于硬件实现,那么发现偏旁部首则更加适合软件实现,从中我们也能够分析出中国人和西方人的思维之差别。继续往下说。发现”木字旁“之后。杨。林,棵形成了冲突链表,但大大降低了匹配候选字的数量。不想遍历的话。须要再次hash,新华字典设计了笔画数这个再hash函数,”林“字除了偏旁之外还剩下4笔画。于是定位到了”林“。假设还冲突,那就须要遍历了,由于商务印书馆可能想不出什么hash函数了(我不知道这样的汉字部首查字法是谁发明的,就当是出版社的杰作吧...)。

反过来看英文查法。总是能够终于确定性定位,由于它的不断hash的hash函数是”取连续字符“,加之单词长度有限且一维排列顺序递进。总是能够到最后一个字符的。

看出差别了吗?看出trie树查询和hash查询的差别了吗?

5.hash路由表和trie路由表

对于hash路由表查询而言,最长前缀匹配逻辑并没有包括在hash过程中,它来自于一种冒险行为,前提是对hash函数的足够自信。hash路由表查找直接从32位前缀hash表開始。逐步回归到0位前缀hash表,期望在这个过程中能高速得到第一个结果,这第一个匹配结果就是终于结果。
       对于trie路由表查询而言,最长前缀匹配逻辑包括在不断再hash的逻辑中。它匹配的是最后一个结果而不是第一个,由于”顺序取某些bits“不断hash的过程。最后匹配到的显然是最精确的。这是和hash路由查询的本质差别。trie查询没有冒险行为,它不须要冒遍历超长冲突链表之险,由于老老实实地运行顺序取bits这个过程总能将查询过程引到目的地。

6.海量路由项的情况

Linux之所以用了那么久hash路由表组织,是由于它足够了。

由于在大部分时间。路由表项数量是不多的。即便是遍历也不会有太大的开销,而hash的计算会大大降低遍历的开销,所谓的冒险最坏情况就是遍历整个路由项,这不是为题。可是一旦遍历整个路由表的全部路由项真的成了一个大风险的时候。或者说即使遍历一半也吃不消的时候,用hash就不明智了。

这和狮子追羚羊时的博弈相似。一个风险是一顿饭,一个风险是一条命,这是严格不正确称的。所以总是看到羚羊胜利(还真不能把这个当零和游戏,由于狮子有时真的不在乎)。
       如今的问题是,怎样使用hash路由表并降低风险。我们先看一下Linux自己的hash函数:

static inline u32 fn_hash(__be32 key, struct fn_zone *fz)
{u32 h = ntohl(key)>>(32 - fz->fz_order);h ^= (h>>20);h ^= (h>>10);h ^= (h>>5);h &= FZ_HASHMASK(fz);return h;
}

可见它将输入的非0项散列得足够开,可是hash的本质就是大空间往小空间映射。冲突在所难免。

有人提出(比方我)在海量路由表项时将长冲突链表组织成trie树的形式,可是这有意义吗?假设是一个完整的trie路由表。最长32步(考虑压缩和回溯)就能找到结果。假设採用hash+trie的方式,每一步的最坏结果都是32步,一共进行32步...这样做没有意义。
       海量路由表项时,hash小空间是严格有范围的。能够觉得它是固定的。平均情况非常easy通过地址空间和hash空间求得,最坏情况则是全然遍历。平均情况假设都不能接受,难道值得为最好情况去冒险吗?因此,千万别用hash表存储海量路由表项。
       可是。还没完

7.局部性利用以及DoS

32位系统,CPU Cache相比内存而言非常小,怎么能够带来如此大的优化?全部映射到同一个cache line的地址都是冲突的啊...这是由于CPU Cache利用了程序的时间/空间局部性,而对于路由而言。则没有空间局部性。时间局部性能够用于路由cache,然而用于路由表本身则有难度。路由表和CPU Cache的差别在于它是全然的。不存在被替换和老化的问题。因此能够把好的hash函数用于单独的路由cache,而路由表仅仅用于路由cache不命中的情况下去匹配。

理想情况分析完了,剩下的仅仅是悲哀了。
       网络訪问的时间局部性真的能够利用吗?尽管一个5元组的数据流通常会随着时间持续经过路由器,可是假设hash冲突的还有一个数据流也经过的话,就会造成cache抖动,在CPU Cache看来。这个问题能够通过控制task切换或者添加cache line唯一键值来解决,可是对于网络訪问,你没法阻止不论什么一个数据包的到来,仅仅要到来就要查询路由表,就有可能导致cache抖动。更严重的。路由cache非常easy受到精心构造的数据包的攻击造成不可用,频繁的替换或者无限的加长链表。平添了查询开销。
       因此设计一个全然的转发表而不是利用路由cache更加能提升转发效率。

这又一次为我的DxR Pro结构作了一个广告。

转载于:https://www.cnblogs.com/mfrbuaa/p/5248393.html

海量路由表能够使用HASH表存储吗-HASH查找和TRIE树查找相关推荐

  1. 海量路由表可以使用HASH表存储吗-HASH查找和TRIE树查找

    千万别!很多人这样说,也包括我. Linux内核早就把HASH路由表去掉了,现在就只剩下TRIE了,不过我还是希望就这两种数据结构展开一些形而上的讨论. 1.hash和trie/radix hash和 ...

  2. 0x14.基础数据结构 — hash表与字符串hash

    目录 一.Hash表 1.AcWing 137. 雪花雪花雪花 0.hash表+链表 1.字符串的最小表示法 二.字符串hashhashhash 0.AcWing 138. 兔子与兔子 1.luogu ...

  3. 用链表和数组实现HASH表,几种碰撞冲突解决方法

    Hash算法中要解决一个碰撞冲突的办法,后文中描述了几种解决方法.下面代码中用的是链式地址法,就是用链表和数组实现HASH表. he/*hash table max size*/ #define HA ...

  4. e - 数据结构实验之查找五:平方之哈希表_面试中常被问到的Hash表,你了解吗

    #新人扶持计划# Hash表在面试中经常被问到,今天我们来了解下. Hash表也称散列表,也有直接译作哈希表,Hash表是一种特殊的数据结构,它同数组.链表以及二叉排序树等相比较有很明显的区别,它能够 ...

  5. 数据结构:通过hash表建立一个宝可梦图鉴管理系统

    1. 建立工程文件夹 bin.obj.src.include 2.创建主makefile文件 OBJS:=test.o pokemon.o CC:=gcc CFLAGS:=-c -g -Wall My ...

  6. 哈希表(散列表)—Hash表解决地址冲突 C语言实现

    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.具体的介绍网上有很详 ...

  7. hash表和在java的实现

    这篇博客主要探讨Hash表中的一些原理/概念,及根据这些原理/概念,自己设计一个用来存放/查找数据的Hash表,并且与JDK中的HashMap类进行比较. 我们分一下七个步骤来进行. 一.    Ha ...

  8. Hash表分析以及Java实现

    这篇博客主要探讨Hash表中的一些原理/概念,及根据这些原理/概念,自己设计一个用来存放/查找数据的Hash表,并且与JDK中的HashMap类进行比较. 我们分一下七个步骤来进行. 一.    Ha ...

  9. hash表的创建,插入数据,查询数据(包含代码)

    本文章采用的是hash表的链地址存储方式 Hash表的含义 Hash表,又称散列表.在前面讨论的顺序.折半.分块查找和树表的查找中,其ASL的量级在O(n)-O(log2n)之间.不论ASL在哪个量级 ...

最新文章

  1. JavaScript 设计模式的七大原则(未完成)
  2. 笔记本电源适配器的选择方法
  3. 科大星云诗社动态20210301
  4. java泛型与接口_Java泛型用于方法,类和接口
  5. redirect_uri 域名与后配置不一致是什么意思_免费 amp; 无限的域名/企业邮箱
  6. 魅族发布会邀请函来了!“无字天书”的秘密明晚揭晓
  7. mysql存储过程和自定义函数_MySQL存储过程/存储过程与自定义函数的区别
  8. QMutexLocker作用范围
  9. Atitit 使用js nodejs进行图像处理ocr的解决方案attilax总结
  10. 实时高清渲染:Shadows
  11. 银联卡跨行业务地区代码标准JSON版
  12. 手机号码检测开通微信查询方法
  13. 网易buff服务器不稳定,《梦幻西游》手游平民94方寸逆袭成神分享心得助你腾飞_ 《梦幻西游》手游官网-人人都玩,无处不在...
  14. 《经济机器是怎样运行的》笔记(二)
  15. win10右键英特尔显卡控制面板不见了(如何打开英特尔® 显卡的控制面板 )
  16. 火线安全:Log4j2 史诗级漏洞波及全球6万+开源软件
  17. sxt_1_struts2入门_hello
  18. UltraISO(软碟通)制作U盘启动盘完整教程
  19. ROS-control-gazebo-moveit-grasp(一、场景搭建)
  20. C#代码实现 - 扑克牌排序

热门文章

  1. 【linux系统】maven安装
  2. php安装redis扩展详细步骤 不会可以加QQ
  3. 基于Python——实现远程下载sftp文件(只下载.zip文件)
  4. 【Android开发】Android 删除指定文件和文件夹
  5. 31全志r58平台Android4.4.2下打开USB摄像头
  6. xshell添加脚本
  7. 特征筛选(随机森林)
  8. idea刷新项目、清除项目缓存
  9. 解决安卓中单个dex方法数超过65535的方法
  10. mac添加取消开机启动