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

千万别!很多人这样说,也包括我。
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小空间是严格有范围的,可以认为它是固定的,平均情况很容易通过地址空间和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很容易受到精心构造的数据包的攻击造成不可用,频繁的替换或者无限的加长链表,平添了查询开销。
       因此设计一个完全的转发表而不是利用路由cache更加能提升转发效率。这又一次为我的DxR Pro结构作了一个广告。

时间: 2024-12-19 07:12:37

海量路由表可以使用HASH表存储吗-HASH查找和TRIE树查找的相关文章

trie树查找和hash查找比较(大量数据)

trie树代码 #include<iostream> #include<stdio.h> #include<iostream> #include<string> #include<stdlib.h> #include<fstream> #include<sstream> #include<vector> #include<string> #include<time.h> using na

hash表总结

Hash表也称散列表,也有直接译作哈希表,Hash表是一种特殊的数据结构,它同数组.链表以及二叉排序树等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找.这个源于Hash表设计的特殊性,它采用了函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够很快速地进行查找. 1.Hash表的设计思想 对于一般的线性表,比如链表,如果要存储联系人信息: 张三 13980593357 李四 15828662334 王五 13409821234 张

[转]Hash表

转自:http://www.cnblogs.com/dolphin0520/ Hash表 Hash表也称散列表,也有直接译作哈希表,Hash表是一种特殊的数据结构,它同数组.链表以及二叉排序树等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找.这个源于Hash表设计的特殊性,它采用了函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够很快速地进行查找. 1.Hash表的设计思想 对于一般的线性表,比如链表,如果要存储联系人信息: 张

【POJ 3274】Gold Balanced Lineup (stl map )设计hash表,处理碰撞

题目链接 题目链接 http://poj.org/problem?id=3274 题意 输入每头牛的特征的10进制,若i~j头牛中每个数位的特征相等则满足要求,求所有满足要求的j-i的最大值. 解题思路 抽屉原理,用前缀和处理每个数位即可. 直接暴力的话复杂度太大了,所以需要取巧的办法. 直接暴力求解是sum[i][p] - sum[j][p] == sum[i][0] - sum[j][0].其中i表示第i头牛,j表示第j头牛,p表示第p个特征,i > j. 取巧的办法:sum[i][p] -

海量路由表的快速检索问题-Hash/Trie/快速交换

在论坛上经常会有人问,到底是使用Trie算法保存路由表还是用Hash算法.那么我首先要明白,你要保存多大的路由表.简单的答案如下:少量:Hash算法大量:Trie算法但是,仅仅这么回答会显得很业余,真的很业余.但是如果回答多了,恐怕也不是什么好事,关键看问者是谁,目的做甚.因此简单且完整的回答必须毫无针对性,只能写作日志供日后回忆了. 以Linux内核为例,如果是少量的路由表,Hash算法的性能会很高,一共32个Hash桶,每一个前缀一个,所有的路由表项挂在这些Hash桶的冲突 链表上,由于路由

hash表简单实现

查找算法大总结: http://www.cnblogs.com/maybe2030/p/4715035.html#_label6 常用的hash函数: http://blog.csdn.net/mycomputerxiaomei/article/details/7641221 什么是哈希表(Hash)? 我们使用一个下标范围比较大的数组来存储元素.可以设计一个函数(哈希函数, 也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标)相对应,于是用这个数组单元来存储这个元素:也可以简单的

十一、从头到尾彻底解析Hash 表算法

在研究MonetDB时深入的学习了hash算法,看了作者的文章很有感触,所以转发,希望能够使更多人受益! 十一.从头到尾彻底解析Hash 表算法 作者:July.wuliming.pkuoliver  出处:http://blog.csdn.net/v_JULY_v.  说明:本文分为三部分内容,    第一部分为一道百度面试题Top K算法的详解:第二部分为关于Hash表算法的详细阐述:第三部分为打造一个最快的Hash表算法.----------------------------------

Hash表算法

出处:http://blog.csdn.net/v_JULY_v 第一部分:Top K 算法详解问题描述百度面试题:    搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节.    假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个.一个查询串的重复度越高,说明查询它的用户越多,也就是越热门.),请你统计最热门的10个查询串,要求使用的内存不能超过1G. 必备知识:    什么是哈希表?    哈希

从头到尾彻底解析Hash 表算法

在研究MonetDB时深入的学习了hash算法,看了作者的文章很有感触,所以转发,希望能够使更多人受益! 十一.从头到尾彻底解析Hash 表算法 作者:July.wuliming.pkuoliver  出处:http://blog.csdn.net/v_JULY_v.  说明:本文分为三部分内容,    第一部分为一道百度面试题Top K算法的详解:第二部分为关于Hash表算法的详细阐述:第三部分为打造一个最快的Hash表算法.----------------------------------