海量路由表能够使用HASH表存储吗-HASH查找和TRIE树查找
非常多人這樣說,也包括我。
Linux內核早就把HASH路由表去掉了。如今就僅僅剩下TRIE了,只是我還是希望就這兩種數據結構展開一些形而上的討論。
1.hash和trie/radix
hash和tire事實上是能夠統一在一起的。具有同樣hash值的多個項具有一個共同的特征,這個特征怎么提取呢?無疑這就是hash函數的工作。而trie樹(或者radix樹,管它呢)的一棵子樹也有共同的特征,這個特征怎么提取呢?無疑這就是該子樹根節點的父節點指示的某些bits在這棵子樹的每個節點都具有同樣的值。
?????? 實際上,trie樹就是hash的一種特殊形式,其hash函數為:取某些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函數:
可見它將輸入的非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树查找的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对于干燥的B级绝缘发电机定子绕组而言,通
- 下一篇: ORA-28001: the passw