千万别!

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

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结构作了一个广告。

海量路由表能够使用HASH表存储吗-HASH查找和TRIE树查找的更多相关文章

  1. NGINX(三)HASH表

    前言 nginx的hash表有几种不同的种类, 不过都是以ngx_hash_t为基础的, ngx_hash_t是最普通的hash表, 冲突采用的是链地址法, 不过这里冲突的元素不是一个链表, 而是一个 ...

  2. Hash表

    Hash表 Hash表也称散列表,也有直接译作哈希表,Hash表是一种特殊的数据结构,它同数组.链表以及二叉排序树等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字 ...

  3. java数据结构之hash表

    转自:http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html Hash表也称散列表,也有直接译作哈希表,Hash表是一种特 ...

  4. 索引,B+ tree,动态hash表

    数据库课索引部分的学习笔记. 教材: Database System: The Complete Book, Chapter 15 Database System Implementation, Ch ...

  5. 经典递归问题:0,1背包问题 kmp 用遗传算法来解背包问题,hash表,位图法搜索,最长公共子序列

    0,1背包问题:我写笔记风格就是想到哪里写哪里,有很多是旧的也没删除,代码内部可能有很多重复的东西,但是保证能运行出最后效果 '''学点高大上的遗传算法''' '''首先是Np问题的定义: npc:多 ...

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

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

  7. Hash表及hash算法的分析

    Hash表中的一些原理/概念,及根据这些原理/概念: 一.       Hash表概念 二.       Hash构造函数的方法,及适用范围 三.       Hash处理冲突方法,各自特征 四.   ...

  8. Anagrams(hash表)

    Given an array of strings, return all groups of strings that are anagrams. Note: All inputs will be ...

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

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

随机推荐

  1. [RxJS] Displaying Initial Data with StartWith

    You often need to render out data before you stream begins from a click or another user interaction. ...

  2. [Cycle.js] Making our toy DOM Driver more flexible

    Our previous toy DOM Driver is still primitive. We are only able to sends strings as the textContent ...

  3. HDOJ 4937 Lucky Number

    当进制转换后所剩下的为数较少时(2位.3位),相应的base都比較大.能够用数学的方法计算出来. 预处理掉转换后位数为3位后,base就小于n的3次方了,能够暴力计算. . .. Lucky Numb ...

  4. resin安装和配置

    1 从 http://www.caucho.com/download/ 下载resin 2 检查你的linux环境,查看是否安装了 jdk1.5 或以上版本,是否安装了perl. 输入命令:Java ...

  5. Javascript基础form表单

    <!DOCTYPE HTML> <html> <head> <script type="text/javascript" charset= ...

  6. redis使用Java学习

    一.连接到redis服务 import redis.clients.jedis.Jedis; public class RedisJava { public static void main(Stri ...

  7. 集合运算符之全集、交集、补集【weber出品必属精品】

    集合的概念 与数学中的全集.交集.补集的概念是一样的 常用的集合运算符 集合运算符的作用:把两个查询构造为一个联合查询 1. 全集:求连个查询的全集 union all:将两个查询的所有数据全部列出, ...

  8. Mvc htmlhelper that generates a menu from a controller

    Simple menu system that grabs a list of actions from a single controller and creates an unordered li ...

  9. UVA 10791 Minimum Sum LCM

    唯一分解定理 把n分解为 n=a1^p1*a2^p2*...的形式,易得每个ai^pi作为一个单独的整数最优. 坑: n==1     ans=2: n因子种数只有一个     ans++: 注意溢出 ...

  10. FMDB官方使用文档-GCD的使用-提高性能(翻译)

    FMDB官方使用文档-GCD的使用-提高性能(翻译) 发布于:2013-08-19 10:01阅读数:13395 由于FMDB是建立在SQLite的之上的,所以你至少也该把这篇文章从头到尾读一遍.与此 ...