node
Kademlia將網絡設計爲具備160層的二叉樹,樹最末端的每一個葉子看做爲節點,節點在樹中的位置由一樣是160bit的節點ID決定。每一個bit的兩種可能值(0或1),決定了節點在書中屬於左邊仍是右邊的子樹,160下來,每一個節點ID便都有一個肯定的位置;算法
Kad網絡中每一個節點都有一個160bit的ID值做爲標誌符,Key也是一個160bit的標誌符,每個加入Kad網絡的節點都會被分配一個160bit的節點ID(node ID),這個ID值是隨機產生的。同時<key, value>對的數據就存放在ID值距離key值最近的若干個節點上。緩存
網絡
x ^ x = 0 //本身於本身的距離爲0併發
x ^ y > 0 // 不一樣節點間必有距離異步
x ^ y = y ^ x // x到y的距離等於y到x的距離分佈式
x ^ y + y ^ z >= x ^ z //從a經b繞到c, 要比直接從a到c距離長工具
x + y >= x ^ y //暫不理解性能
(x ^ y) ^ (y ^ z) = x ^ z //暫不理解spa
所說的距離是邏輯上的距離,與地理位置無關,因此有可能兩個節點之間計算獲得的邏輯距離很近,但實際上地理上的距離卻很遠 。
例如:節點A的ID(011)和節點B的ID(101)距離:011 ⊕ 101 = 110 = 4+2 = 6。
當咱們把全部節點ID都按照上述步驟操做後,會發現,這些節點造成一顆二叉樹。
(實例僅演示三層)
每個節點均可以從本身的視角出發來對二叉樹進行拆分。
拆分規則是從根節點開始,把不包含本身的子樹拆分出來,而後在剩下的子樹再拆分不包含本身的下一層子樹,以此類推,直到最後只剩下本身。如上圖所示,以節點ID爲6(110)爲視角進行拆分,能夠獲得3個子樹(灰色圓圈)。而以節點101爲視角拆分,則能夠獲得以下二叉樹。
節點101的角度
Kad默認的散列值空間是m=160(散列值有160bit),因此拆分之後的子樹最多有160個。而考慮到實際網絡中節點個數遠遠沒有2^160個,因此子樹的個數明顯小於160個。
對於每一個節點,當按照本身的視角對二叉樹進行拆分之後,會獲得n個子樹。對於每一個子樹,若是都分別知道里面1個節點,那麼就能夠利用這n個節點進行遞歸路由,從而能夠達到整個二叉樹的任何一個節點。
假設每一個節點ID是N bits。每一個節點按照本身視角拆分完子樹後,一共能夠獲得N個子樹。
warning:上面說了,只要知道每一個子樹裏的一個節點就能夠實現全部節點的遍歷。可是,在實際使用過程當中,考慮到健壯性(每一個節點可能推出或者宕機),只知道一個節點是不夠的,須要之多多幾個節點才比較保險。
因此,在Kad論文中舊有一個K-桶(K-bucket)的概念。也就是說,每一個節點在完成拆分子樹之後,要記錄每一個子樹裏面K個節點。這裏K是一個系統級常量,由軟件系統本身設定(BT下載使用的Kad算法中,K設定爲8)。
K桶在這裏實際上就是路由表。每一個節點按照本身視角拆分完子樹後,能夠獲得N個子樹,那麼就須要維護N個路由表(對應N個K-桶)。
Kad算法中就使用了K-桶的概念來存儲其餘鄰近節點的狀態信息(節點ID、IP和端口),以下圖,對於160bit的節點ID,就有160個K-桶。
對於每個K-桶i,它會存儲與本身距離在區間[2^i, 2^(i+1)) 範圍內的K個節點的信息,以下圖所示。每一個K-桶i中存儲有K個其餘節點信息,在BitTorrent中K取8。固然每個K-桶i不可能把全部相關的節點都存儲,這樣表根本存儲不下。它是距離本身越近的節點存儲的越多,離本身越遠存儲的越少(只取距離本身最近的K個節點),以下圖所示。
同時每一個K-桶中存放的位置是根據上次看到的時間順序排列,最先訪問的放在頭部,最新訪問的放在尾部。
任何節點均可以發起FIND_NODE(查詢節點)的請求,從而刷新K-桶中的節點信息
當收到其餘節點發送過來的請求(如:FIND_NODE、FIND_VALUE),會把對方的節點ID加入到某個K-桶中
經過發起PING請求,判斷K-桶中某個節點是否在線,而後清理K-桶中哪些下線的節點
當一個節點ID要被用來更新對應的K-桶,其具體步驟以下:
咱們能夠看到K-桶的更新機制實現了一種把最近看到的節點更新的策略,也就是說在線時間長的節點有較高的可能性可以繼續保留在K-桶列表中。
這種機制提升了Kad網絡的穩定性並降少了網絡維護成本(減小構建路由表),同時這種機制能在必定程度上防護DDOS攻擊,由於只有老節點失效後,Kad纔會更新K-桶,這就避免了經過新節點加入來泛洪路由信息。
Kad算法一共有4中消息類型:
備註:每一個發起請求的RPC消息都會包含一個發送者加入的隨機值,這個能夠確保在接收到消息響應的時候能夠根前面發送過的消息匹配。
節點查詢能夠同步進行也能夠異步進行,同時查詢的併發數量通常爲3。
當節點要查詢<key, value>數據對時,和定位節點的過程相似。
若是上述FIND_VALUE最終找到value值,則<key, value>數據對會緩存在沒有返回value值的最近節點上,這樣下次再查詢相同的key值時就能夠加快查詢速度。
因此,越熱門的資源,其緩存的<key, value>數據對範圍就越廣。這也是爲何咱們之前用P2P下載工具,下載的某個資源的人越多時,下載速度越快的緣由。
當節點收到一個<key, value>的數據時,它的存儲過程以下:
新節點想要加入Kad網絡,其步驟以下:
節點A在自我定位創建路由表的同時,也使得其餘節點可以使用節點A的ID來更新他們的路由表。這過程讓節點A得到詳細路由表的同時,也讓其餘節點知道A節點的加入。
轉自《https://shuwoom.com/?p=813》