P2P網絡中的DHT分佈式哈希結構

現有的P2P實現可以分爲三種類型。它們分別是:基於目錄服務器P2P,非結構化P2P和結構化P2P。基於目錄服務器這一類系統中設置目錄服務器,用於保存用戶節點的地址信息和該節點上共享文件的描述信息,文件本身是分散存貯在各個節點上的,實際的文件傳輸也是在對等節點之間進行,目錄服務器僅僅起到中介作用,爲節點提供發佈和查詢文件索引服務。鑑於集中式目錄服務器不僅可能成爲系統的瓶頸,而且還可能引發法律糾紛,因此出現了以Gnutella爲代表的非結構化P2P系統,在這種P2P結構中,文件索引信息不再由集中式的目錄服務器存儲和管理,而是分散到網絡中,由節點自己保存,該類系統採用分佈式的索引查找策略,爲了查找網絡中的文件,節點要隨機地維護網絡中的其他一些節點作爲鄰居,以便通過鄰居節點廣播查詢報文。非結構化P2P系統中由於不存在目錄服務器,所以沒有單點瓶頸問題,不存在單一故障點。然而其缺點也是明顯的:在網絡中廣播查詢報文加重了網絡通信負擔,其查詢機制在系統規模擴大時不具有可擴展性。另外,由於查詢報文被限制在特定的範圍內,所以並不能保證一定可以找到網絡中存在的目的數據。上面介紹的兩類P2P系統都缺乏有效的、可擴展的索引查找機制。爲此,近年來許多研究小組在設計可擴展的查找機制方面做了大量的研究工作,提出了Chord、Pastry、CAN和Tapestry等用於構建結構化P2P的分佈式哈希表系統(Distributed Hash Table,DHT)。DHT的主要思想是:首先,每條文件索引被表示成一個(K, V)對,K稱爲關鍵字,可以是文件名(或文件的其他描述信息)的哈希值,V是實際存儲文件的節點的IP地址(或節點的其他描述信息)。所有的文件索引條目(即所有的(K, V)對)組成一張大的文件索引哈希表,只要輸入目標文件的K值,就可以從這張表中查出所有存儲該文件的節點地址。然後,再將上面的大文件哈希表分割成很多局部小塊,按照特定的規則把這些小塊的局部哈希表分佈到系統中的所有參與節點上,使得每個節點負責維護其中的一塊。這樣,節點查詢文件時,只要把查詢報文路由到相應的節點即可(該節點維護的哈希表分塊中含有要查找的(K,V)對)。這裏面有個很重要的問題,就是節點要按照一定的規則來分割整體的哈希表,進而也就決定了節點要維護特定的鄰居節點,以便路由能順利進行。這個規則因具體系統的不同而不同,CAN,Chord,Pastry和Tapestry都有自己的規則,也就呈現出不同的特性。基於分佈式哈希表(DHT)的分佈式檢索和路由算法因爲具有查找可確定性、簡單性和分佈性等優點,正成爲國際上結構化P2P網絡研究和應用的熱點。自2002年起,美國國家科學基金會(NSF)提供了1200萬美元的資金啓動了一個爲期5年的研究項目IRIS,該項目集中了MIT和UC Berkeley等5所著名高等院校的強大科研力量,爲下一代大規模分佈式應用研製基於DHT的新型基礎設施。

分佈式哈希表在節點失效、遭受攻擊和突發性高負載面前都能表現出很好的健壯性;它具有良好的可擴展性,能以較低系統開銷獲得較大的系統規模;可以自我配置,不需要手工干預就可以自動把新加入節點合併到系統中;能提供簡單靈活的接口,可以爲多個P2P應用同時使用。
1     Chord

Chord是UC Berkeley和MIT共同提出的一種分佈式查找算法,目的是爲了能在P2P網絡中查找數據。給定一個關鍵字,Chord可以有效地把該關鍵字映射到網絡中某個節點上。因而在P2P網絡中只要給每個數據V都賦予一個關鍵字K,就可以利用Chord在該關鍵字映射的節點上存儲或提取相應的(K, V)對。Chord的突出特點是算法簡單,而且可擴展 - 查詢過程的通信開銷和節點維護的狀態隨着系統總節點數增加成指數關係。Chord的路由性能優於CAN,而節點加入過程和維護開銷又優於Tapestry和Pastry。

 

Chord的設計:Chord中每個關鍵字和節點都分別擁有一個m比特的標識符。關鍵字標識符K通過哈希關鍵字本身得到,而節點標識符N則通過哈希節點的IP地址得到。哈希函數可以選用SHA-1。所有節點按照其節點標識符從小到大(取模2m後)沿着順時針方向排列在一個邏輯的標識圓環上(稱爲Chord環)。Chord的映射規則是:關鍵字標識爲K(K, V)對存儲在這樣的節點上,該節點的節點標識等於K或者在Chord環上緊跟在K之後,這個節點被稱爲K的後繼節點,表示爲successor(K)因爲標識符采用m位二進制數表示,並且從0到2m-1順序排列成一個圓圈,succesor(K)就是從K開始順時針方向距離K最近的節點。

上圖給出了一個m=6Chord環,環中分佈了10個節點,存儲了5個關鍵字,節點標識前加上N而關鍵字前加上K以示區別。因爲successor(10)=14,所以關鍵字10存儲到節點14上。同理,關鍵字2430存儲到節點32上,關鍵字38存儲到節點38上,而關鍵字54則存儲到節點56上。當網絡中的參與節點發生變動時,上面的映射規則仍然要成立。爲此,當某節點n加入網絡時,某些原來分配給n的後繼節點的關鍵字將分配給n。當節點n離開網絡時,所有分配給它的關鍵字將重新分配給n的後繼節點。除此之外,網絡中不會發生其他的變化。以上圖爲例,當標識爲26的節點接入時,原有標識爲32的節點負責的標識爲24的關鍵字將轉由新節點存儲。顯然,爲了能在系統中轉發查詢報文,每個節點要了解並維護chord環上相鄰節點的標識和IP地址,並用這些信息構成自身的路由表。有了這張表,Chord就可以在環上任意兩點間進行尋路。

 Chord的路由:Chord中每個節點只要維護它在環上的後繼節點的標識和IP地址就可以完成簡單的查詢過程。對特定關鍵字的查詢報文可以通過後繼節點指針在圓環上傳遞,直到到達這樣一個節點:關鍵字的標識落在該節點標識和它的後繼節點標識之間,這裏的後繼節點就是存儲目標(K, V)對的節點。

上圖給出了一個示例,節點8發起的查找關鍵字54的請求,通過後繼節點依次傳遞,最後定位到存儲有關鍵字54的節點56。在這種簡單查詢方式中,每個節點需要維護的狀態信息很少,但查詢速度太慢。若網絡中有N個節點,查詢的代價就爲O(N)數量級。因而在網絡規模很大時,這樣的速度是不能接受的。

爲了加快查詢的速度,Chord使用擴展的查詢算法。爲此,每個節點需要維護一個路由表,稱爲指針表(finger table)。如果關鍵字和節點標識符用m位二進制位數表示,那麼指針表中最多含有m個表項。節點n的指針表中第i項是圓環上標識大於或等於n+2i-1的第一個節點(比較是以2m爲模進行的)。例如若s=successor(n+2i-1), 1im,則稱節點s爲節點n的第i個指針,記爲n.finger[i]n.finger[1]就是節點n的後繼節點。指針表中每一項既包含相關節點的標識,又包含該節點的IP地址(和端口號)。

上圖給出了節點8的指針表,例如節點14是環上緊接在(8+20) mod 26=9之後的第一個節點,所以節點8的第一個指針是節點14;同理因爲節點42是環上緊接在(8+25) mod 26=40之後的第一個節點,所以節點8的第6個指針是節點42維護指針表使得每個節點只需要知道網絡中一小部分節點的信息,而且離它越近的節點,它就知道越多的信息。但是,對於任意一個關鍵字K,節點通常無法根據自身的指針表確定的K的後繼節點。例如,下圖中的節點8就不能確定關鍵字34的後繼節點,因爲環上34的後繼節點是38,而節點38並沒有出現在節點8的指針表中。

擴展的查詢過程是:任何一個節點收到查詢關鍵字K的請求時,首先檢查K是否落在該節點標識和它的後繼節點標識之間,如果是的話,這個後繼節點就是存儲目標(K, V)對的節點。否則,節點將查找它的指針表,找到表中節點標識符最大但不超過K的第一個節點,並將這個查詢請求轉發給該節點。通過重複這個過程,最終可以定位到K的後繼節點,即存儲有目標(K, V)對的節點

節點加入和退出:爲了應對系統的變化,每個節點都週期性地運行探測協議來檢測新加入節點或失效節點,從而更新自己的指針表和指向後繼節點的指針。新節點n加入時,將通過系統中現有的節點來初始化自己的指針表。也就是說,新節點n將要求已知的系統中某節點爲它查找指針表中的各個表項。在其他節點運行探測協議後,新節點n將被反映到相關節點的指針表和後繼節點指針中。這時,系統中一部分關鍵字的後繼節點也變爲新節點n,因而先前的後繼節點要將這部分關鍵字轉移到新節點上。當節點n失效時,所有指針表中包括n的節點都必須把它替換成n的後繼節點。爲了保證節點n的失效不影響系統中正在進行的查詢過程,每個Chord節點都維護一張包括r個最近後繼節點的後繼列表。如果某個節點注意到它的後繼節點失效了,它就用其後繼列表中第一個正常節點替換失效節點。

2     Pastry
Microsoft研究院和Rice大學共同提出的Pastry是用於廣域P2P應用的分佈式查找和路由系統。Pastry系統中的每個節點都有一個唯一的節點號(nodeId),每條消息都有一個關鍵字。Pastry可以把消息路由到nodeId和關鍵字在數值上最接近的那個節點。每個Pastry節點維護節點號空間中和它直接相鄰的鄰居節點信息。當發生新節點加入、已有節點失效或恢復事件時,Pastry節點會通知上層應用。Pastry是完全分佈式的、可擴展的和自組織的,它能夠自動應對節點加入、離開和失效。

 Pastry的設計:Pastry是自組織的重疊網絡,每個節點都被分配一個128位的nodeId。nodeId用於在圓形的節點空間中(從0到2128-1)標識節點的位置,它是在節點加入系統時隨機分配的,隨機分配的結果是使得所有的nodeId在128位的節點號空間中均勻分佈。nodeId可以通過計算節點公鑰或者IP地址的哈希函數值來獲得。

假設網絡包含N個節點,Pastry可以把一個給定的關鍵字路由到nodeId和該關鍵字最接近的節點。即使同時發生節點失效,Pastry也可以保證關鍵字送達目標節點,除非nodeId和關鍵字臨近的節點中有|L|/2個同時失效(|L|是配置參數,典型值取16或32)。爲了進行路由,Pastry把nodeId和關鍵字表示爲一串以2b爲基的數,查詢消息被路由到nodeId和關鍵字在數值上最接近的節點。方法是:每個節點把查詢消息轉發給下一個節點時,要保證這個節點的nodeId和關鍵字的相同前綴至少要比當前節點的nodeId和關鍵字的相同前綴長一個數位(即b個比特)。如果找不到這樣的鄰居節點,消息將轉發給前綴長度相同但是節點號數值更接近關鍵字的節點。爲此,每個Pastry節點都需要維護狀態表:一張路由表,一個鄰居節點集和一個葉子節點集。

nodeId爲10233102的Pastry節點維護的狀態示意圖

上圖給出了一個節點維護的數據示意圖,b取值爲2,所有的數均是4進制的。其中路由表的最上面一行是第0行。路由表中每行的陰影項表示當前節點號中相應的數位。路由表中每項節點的nodeId表示格式是“相同前綴 + 下一數位 + nodeId的剩餘位”。圖中沒有列出相關節點的IP地址。

路由表每行包括2b-1個表項。第n行的2b-1個表項中,每個節點nodeId的前n個數位和當前節點nodeId的前n個數位相同,而第n+1個數位和當前節點不同。b的取值是路由表大小和任意兩節點間需要的最大路由跳數之間的折衷。例如,當b取4而網絡中有106 個節點時,每個節點的路由表平均包括75個表項,預期的路由跳數是5。如果網絡中有109個節點,則路由表平均會有105項,而預期的路由步數也將增加到7。
葉子節點集維護的是nodeId和本節點最接近的節點,其中一半是nodeId大於當前節點的,另一半是nodeId小於當前節點的。葉子節點集在路由時需要用到。鄰居節點集維護按給定的評測指標距離本節點最近的節點,正常的路由過程並不使用鄰居節點集,它的主要作用是維護路由的本地性。通常這兩個集合的大小分別爲2b或者2×2b
 Pastry的路由過程是:節點收到一條查詢消息時,首先檢查該消息的關鍵字是否落在葉子節點集範圍內。如果是,則直接把消息轉發給對應的節點,也就是葉子節點集中nodeId和關鍵字最接近的節點。如果關鍵字沒有落在葉子節點集範圍內,節點就會把消息轉發給路由表中的一個節點,該節點的nodeId和關鍵字的相同前綴至少要比當前節點的nodeId和關鍵字的相同前綴長一個數位。如果路由表中相應的表項爲空,或者表項中對應的節點不可達,這時候查詢消息將被轉發給前綴長度相同但是節點號數值更接近關鍵字的節點。除非消息已經到達目的節點,否則這樣的節點一定位於葉子節點集中。而且,只要葉子節點集中一半以上的節點不同時失效,就一定可以找到滿足要求的節點。很明顯,路由的每一步都比上一步向目標節點前進了一步,因此路由過程總是收斂的。 
節點加入和退出

新節點加入時需要初始化自身的狀態表,並通知其他節點自己已經加入系統。假定新加入節點的nodeId爲X,同時假定X在加入Pastry之前知道系統中和自己距離相近的節點A。新節點X首先請求A路由一條“加入”消息,消息的關鍵字就是X。這條消息最終會到達nodeId和X最接近的節點Z。作爲應答,節點A、節點Z以及從A到Z的路徑上所有經過的節點都會把自己的狀態表發送給節點X。節點X利用這些信息初始化自己的狀態表,然後節點X再通知其他節點它已經加入了系統。從交換的消息數量上說,節點加入操作的複雜度爲O(log2bN)。

Pastry中節點很可能失效或者突然離開系統。若nodeId空間中的相鄰節點無法和某個節點通信時,就認爲該節點失效了。一旦節點檢測出其葉子節點集L中的某個節點失效,它就會請求該集合中nodeId最大或最小的節點把其葉子節點集L’發送過來。(如果失效節點的nodeId比當前節點的nodeId大,則用葉子集中nodeId最大的節點,反之則用nodeId最小的節點。)當前節點將從L’中選擇一個L中沒有的活動節點來替代失效節點。如果節點檢測出其路由表中某項對應的節點失效,它將從該項所在的路由錶行中選擇另一個節點,要求該節點把路由表中對應位置的項發過來。如果當前節點的路由表中對應行已經沒有可用節點了,那麼當前節點將從路由表的下一行中選擇一個節點,這個過程將繼續到當前節點能夠得到一個替代失效節點的節點號,或者當前節點遍歷了路由表爲止。節點也會週期性地和鄰居節點集中的節點交換信息以檢測這些節點是否仍在Pastry系統中,如果節點檢測出其鄰居節點集中的某個節點失效,它將請求其他鄰居節點把其鄰居節點集發送過來並從中選擇一個新的鄰居節點替換失效節點。
3     CAN
UC Berkeley提出的CAN(Content Addressable Network,內容尋址網絡)實現了文件索引和存放位置的有效映射,不需要任何形式的中央控制點,節點只需要維護少量的控制狀態而且狀態數量獨立於系統中的節點數量,具有完全自組織和分佈式的結構,並且有良好的可擴展性和容錯性。 
CAN的設計
CAN的設計基於虛擬的d維笛卡兒座標空間,這個座標空間完全是邏輯的,和任何物理座標系統都沒有關係。在任何時候,整個座標空間動態地分配給系統中的所有節點,每個節點負責維護獨立的互不相交的一塊區域。CAN中的節點自組織成一個代表這個虛擬座標空間的重疊網絡(overlay network)。每個節點要了解並維護相鄰區域中節點的IP地址,用這些鄰居信息構成自身的座標路由表。有了這張表,CAN可以在座標空間中任意兩點間進行尋路。

下圖給出了一個2維的[0, 1]×[0, 1]的笛卡兒座標空間劃分成五個節點區域的情況。虛擬座標空間採用下面的方法保存(K, V)對。當保存(K1, V1)時,使用統一的哈希函數把關鍵字K1映射成座標空間中的點P。那麼這個值將被保存在該點所在區域的節點中。當需要查詢關鍵字K1對應的值時,任何節點都可以使用同樣的哈希函數找到K1對應的點P,然後從該點對應的節點取出相應的值V1。如果此節點不是發起查詢請求的節點,CAN將負責將此查詢請求轉發到P所在區域的節點上。因此,有效的路由機制是CAN中的一個關鍵問題。

                          五個節點維護的CAN虛平面

 
CAN的路由

CAN中的路由很簡單,沿着座標空間中從發起請求的點到目的點之間的一條路徑轉發即可。爲此,每個CAN節點都要保存一張座標路由表,其中包括它的鄰居節點的IP地址和其維護的虛擬座標區域。兩個節點互爲鄰居是指:在d維座標空間中,兩個節點維護的區域在d-1維的座標上有重疊而在剩下的一維座標上相互鄰接。例如,圖2.6中D和E是鄰接節點,而D和B就不是鄰接節點, 因爲D和B在X軸和Y軸上都鄰接。每條CAN消息都包括目的點座標。路由時節點只要朝着目標節點的方向把消息轉發給自己的鄰居節點即可。下圖給出了查找過程的一個簡單的例子。

如果一個d維空間劃分成n個相等的區域,那麼平均路由長度是(d/4)(n1/d),每個節點只需要維護2d個鄰居節點的信息。這個結果表明CAN的可擴展性很好,節點數增加時每個節點維護的狀態信息不變,而路由長度只是以O(n1/d)的數量級增長。因爲座標空間中兩點之間可以有許多條不同的路徑,所以單個節點的失效對CAN基本上沒有太大的影響。遇到失效節點時,CAN會自動沿着其他的路徑進行路由。 
節點加入和退出

因爲整個CAN空間要分配給系統中現有的全部節點,當一個新的節點加入網絡時必須得到自己的一塊座標空間。CAN通過分割現有的節點區域實現這一過程。它把某個現有節點的區域分裂成同樣大小的兩塊,自己保留其中的一塊而另一塊分給新加入的節點。整個過程分爲以下三步:

1.       新節點首先找到一個已經在CAN中的節點。

2.       新節點使用CAN的路由機制找到一個區域將要被分割的節點。

3.       執行分割操作,然後原有區域的鄰接區域必須被告知發生了分割,這樣新節點才能被別的節點路由到。

當節點離開CAN時,必須保證它的區域被系統中剩餘的節點接管,也即分配給其他仍然在系統中的節點。一般是由某個鄰居節點來接管這個區域和所有的索引數據(K,V)對。如果某個鄰居節點負責的區域可以和離開節點負責的區域合併形成一個大的區域,那麼將由這個鄰居節點執行合併操作。否則,該區域將交給其鄰居節點中區域最小的節點負責。也就是說,這個節點將臨時負責兩個區域。

正常情況下,每個節點向其所有鄰居節點發送週期性的更新消息,消息中包括自身的區域範圍、它的鄰居列表以及這些鄰居節點負責的區域範圍。如果多次沒有接收到某個鄰居的更新消息,那麼節點就認爲這個鄰居失效了。這時,節點將啓動接管機制,並啓動一個時鐘。失效節點的每個鄰居節點相互獨立地執行該過程,每個時鐘大小都和相應節點負責的區域面積成比例。如果時鐘超時,節點將向失效節點的所有鄰居節點發送接管消息,該消息中包括它自己的區域面積信息。當某個節點接收到接管消息後,如果它的區域面積比發出消息的節點大,那麼它將取消接管操作。否則它將發出自己的取代消息。採用這種機制可以有效地選擇面積最小的鄰居節點來接管失效節點。在特殊情況下,還有可能出現多個相鄰的節點同時失效的情況。例如,節點檢測到某個節點失效,但是失效節點地鄰居中超過一半可能都不可達。這時,如果讓該節點接管失效節點地區域,就有可能導致CAN中狀態不一致。所以在這種情況下,CAN在執行修復操作之前,會搜索失效區域附近的節點,搜索逐步擴大直至獲得足夠的鄰居狀態,以便安全地開始接管過程。
 4     Tapestry
Tapestry是UC Berkeley提出的一種新型的P2P網絡定位和路由算法。該算法可以對消息進行與位置無關的路由,把查詢消息傳遞到最近的存儲有目標對象拷貝的節點。Tapestry具有自組織、容錯和負載平衡等特點。每個Tapestry 節點只需維護O(log N)大小的路由表信息,路由最多在O(log N)跳數內完成。
 Tapestry的設計
Tapestry從一個標識符空間中爲每個節點隨機分配一個節點標識符nodeID,對象也從同一個標識符空間中分配一個全局唯一標識符GUID(globally unique identifier)。Tapestry使用SHA-1來產生標識符,使得nodeID和GUID均勻分佈在標識符空間中。爲了討論問題的方便,用Nid來表示節點N的標識符,用OG表示對象O的標識符。Tapestry目前使用160比特的標識符空間,標識符用一個全局統一的進製表示(例如使用16進制,則標識符是一個40位的數字),所有的節點依據標識符自組織成一個重疊網絡。
Tapestry動態地把每個標識符G映射到當前系統中一個節點上,該節點稱爲G的根節點,表示爲GR。如果某節點的Nid=G,則這個節點就是G的根節點。爲了轉發查詢消息,每個節點需要維護一個鄰居映射表,每個表項包括一個鄰居節點的標識符和IP地址。往GR路由時,消息將沿着鄰居指針向節點標識符在標識符空間中更接近G的節點轉發(例如,匹配更大的前綴)。

Tapestry中的每個節點都保存有鄰居映射表。鄰居映射表可以用於把消息按照目的地址一位一位地向前傳遞,比如從4***=>42**98=>42A*=>目的節點42AD(這裏*表示通配符)。這種方式類似於IP分組轉發過程中的最長前綴匹配。節點N的鄰居映射表分爲多個級別,每個級別包含的鄰居節點的數量等於標識符表示法的基數,而每個級別中鄰居節點標識符和本節點標識符的相同前綴都比前一級別多一個數位。也就是說,第j級鄰居表的第i項是標識符以prefix(N, j-1) + “i”爲前綴而且離當前節點最近的鄰居節點。例如,節點325AE的鄰居映射表中第4級第9項是系統中標識符以325 + “9” =3259爲前綴的某個節點。

 

上圖給出了一個節點的鄰居指針實例,從圖中可以看到第一級的鄰居節點標識和本節點標識沒有共同前綴,而第二級的鄰居節點標識都以4開頭,即和本節點標識具有相同的一個數位的前綴。

Tapestry採用的基本查找和路由機制:當一條查找消息到達傳遞過程中的第n個節點時,該節點和目的節點的共同前綴長度至少大於n。爲了進行轉發,該節點將查找鄰居映射表的第n+1級中和目的標識符下一數位相匹配的鄰居節點。轉發過程將在每個節點中依次進行直到到達目的節點。這種方法可以保證路由至多經過logbN個節點就可以到達目的節點,這裏N是節點標識符名字空間的大小,而b是標識符使用的基數。同樣,由於每個節點的鄰居映射表的每個級別只需要保存b個表項,因此,鄰居映射表的空間爲blogbN。

 

上圖給出了Tapestry中一個查詢消息轉發的例子。圖中節點標識符的基數是4,查詢消息從5230發出,目的節點是42AD。

Tapestry中的節點在共享數據時被稱爲服務器,請求數據時被稱爲客戶,轉發消息時被稱爲路由器。也就是說每個節點可以同時具有客戶、服務器和路由器的功能。

服務器S通過向對象O(GUID爲OG)的根節點OR定期的發送消息來報告S保存有對象O。在這條發佈路徑上的每個節點都保存關於這個對象O的位置信息指針<OG, S>,這裏的位置信息只是一個指向S的指針,而並不是對象O的拷貝。當多個都存有同一對象拷貝的服務器分別向根結點發布消息時,路徑上的每個節點按各個服務器離自己的網絡時延遞增的順序保存這些位置指針列表。

當需要定位一個對象O時,客戶向對象O的根節點發出查詢消息,查詢消息轉發路徑上的每個節點都檢查自己是否存有對象O的位置指針,如果有,該節點直接把查詢消息轉發個服務器S,否則,消息將到達O的根節點,然後由根節點把查詢消息轉發給服務器。

Tapestry有一個重要的特性是:查詢消息可以被轉發到距離客戶最近的存有對象拷貝的服務器上。在Tapestry中,從兩個臨近節點向同一個目的節點OR發出兩條消息時,它們的轉發路徑很快就會交叉,這是因爲路由過程的每一步都是使得下一個節點標識符和OR具有更長的相同前綴;到根結點的路徑只是目的標識符的函數,而不是消息發起節點標識符的函數;而且,路由過程中的下一跳鄰居節點是根據網絡距離選擇的,因而客戶離服務器越近,那麼查詢路徑碰到發佈路徑的速度就越快。也就是說,查詢消息會被轉發到最近的服務器上。

 節點加入和退出:Tapestry的節點加入算法和Pastry類似。節點N在加入Tapestry網絡之前,也需要知道一個已經在網絡中的節點G。然後N通過G發出路由自己的節點ID的請求,根據經過的節點的對應的鄰居節點表構造自己的鄰居節點表。構造過程中還需要進行一些優化工作。構造完自己的數據結構後,節點N將通知網絡中的其他節點自己已經加入網絡。通知只針對在N的鄰居映射表中的主鄰居節點和二級鄰居節點進行。

Tapestry採用兩種機制處理節點的退出。一種情況是節點從網絡中自行消失(主要原因是節點失效),在這種情況下,它的鄰居可以檢測到它已經退出網絡並可以相應的調整路由表。另一種機制是節點在退出系統之前通過後向指針通過所有把它作爲鄰居的節點,這些節點會相應調整路由表並通知對象服務器該節點已經退出網絡。檢測正常操作過程中的鏈路和服務器失效,可以使用TCP連接超時機制。除此之外,每個Tapestry節點都使用後向指針週期性的發送“心跳”(heartbeats)UDP分組給把自己加入鄰居映射表的節點。每個節點都可以根據自己收到的心跳分組來決定自己的鄰居映射表中是否有節點失效。在鄰居節點表中,除了主鄰居節點(最近的鄰居)之外,每個路由項還保存了兩個備份的鄰居節點,當檢測到主鄰居節點失效後,鄰居節點表將順序選擇備份鄰居節點。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章