基于DHT 的几种P2P 算法研究

1,引言
    P2P 技术也称对等网络结构(Peer-to-Peer),是通过系统之间直接交换来共享计算机资源和服务的一种应用模式。它在很大程度上颠覆了人们对互联网的传统观念,打破了占据主导地位的客户端服务器(Client/Server)的互联网架构,其最根本的思想就是网络中不存在
中心节点(或中心服务器).每个节点(peer)既可以获取其它节点的资源或服务,同时又是资源或服务的提供者。一般P2P 网络中每一个节点的权利和义务都是对等的,包括通讯、服务和资源消费。

    结构化P2P 用纯分布式的消息路由,目前的主流方法是采用分布式哈希表(DHT)技术。DHT 各节点并不需要维护整个网络的信息,节点仅存储其临近的后继节点信息,因此较少的路由信息就可以有效地实现资源定位。该P2P 网络模式有效减少了资源定位的开销,提高了P2P 网络的可扩展性。 目前基于DHT 的代表性的研究项目主要包括麻省理工学院的Chord、加州大学伯克利分校的CAN和Tapestry、以及微软研究院的Pastry。

2. Chord
2. 1 Chord 原理
    Chord 中每个关键字和节点都分别拥有一个m 比特的标识符。关键字标识符K 通过哈希关键字本身得到,而节点标识符N 则通过哈希节点的IP 地址得到。哈希函数可以选用SHA-1。所有节点按照其节点标识符从小到大(取模2^m 后)沿着顺时针方向排列在一个逻辑的标识圆环上(称为Chord 环)。Chord 的映射规则是:关键字标识为K 的(K, V)对存储在这样的节点上,该节点的节点标识等于K 或者在Chord 环上紧跟在K 之后,这个节点被称为K 的后继节点,表示为successor(K)。因为标识符采用m 位二进制数表示,并且从0 到2^m-1 顺序排列成一个圆圈successor(K)就是从K 开始顺时针方向距离K 最近的节点。

 2.2 Chord 的路由

    为了加快查询的速度,Chord 使用扩展的查询算法。为此,每个节点需要维护一个路由表,称为指针表(finger table)。如果关键字和节点标识符用m 位二进制位数表示,那么指针表中最多含有m 个表项。节点n 的指针表中第i 项是圆环上标识大于或等于n+2^(i-1) 的第一个节点(比较是以2^m 为模进行的)。例如若s=successor(n+2^(i-1)), 1≤i≤m,则称节点s为节点n 的第i 个指针,记为n.finger[i]。n.finger[1]就是节点n 的后继节点。指针表中每一项既包含相关节点的标识,又包含该节点的IP 地址(和端口号)。

    图 1 给出了节点8 的指针表,例如节点14 是环上紧接在(8+2^0) mod 2^6=9 之后的第一个节点,所以节点8 的第一个指针是节点14;同理因为节点42 是环上紧接在(8+2^5) mod 2^6=40之后的第一个节点,所以节点8 的第6 个指针是节点42。维护指针表使得每个节点只需要知道网络中一小部分节点的信息,而且离它越近的节点,它就知道越多的信息。     

    任何一个节点收到查询关键字K 的请求时,首先检查K 是否落在该节点标识和它的后继节点标识之间,如果是的话,这个后继节点就是存储目标(K, V)对的节点。否则,节点将查找它的指针表,找到表中节点标识符最大但不超过K 的第一个节点,并将这个查询请求转发给该节点。通过重复这个过程,最终可以定位到K 的后继节点,即存储有目标(K, V)对的节点。   

      

图1 查询和路由的方法

2.3 节点的加入和退出

       为了应对系统的变化,每个节点都周期性地运行探测协议来检测新加入节点或失效节点,从而更新自己的指针表和指向后继节点的指针。新节点n 加入时,将通过系统中现有的节点来初始化自己的指针表。这时,系统中一部分关键字的后继节点也变为新节点n,因而先前的后继节点要将这部分关键字转移到新节点上。当节点n 失效时,所有指针表中包括n的节点都必须把它替换成n 的后继节点。为了保证节点n 的失效不影响系统中正在进行的查询过程,每个Chord 节点都维护一张包括r 个最近后继节点的后继列表。

3. Pastry
3.1 Pastry 原理
      Pastry 是自组织的重叠网络,每个节点都被分配一个128 位的nodeId。nodeId 用于在圆形的节点空间中(从0 到2^128-1)标识节点的位置,它是在节点加入系统时随机分配的,随机分配的结果是使得所有的nodeId 在128 位的节点号空间中均匀分布。nodeId 可以通过计算节点公钥或者IP 地址的哈希函数值来获得。    

     假设网络包含N 个节点,Pastry 可以把一个给定的关键字路由到nodeId 和该关键字最接近的节点。即使同时发生节点失效,Pastry 也可以保证关键字送达目标节点,除非nodeId和关键字临近的节点中有|L|/2 个同时失效(|L|是配置参数,典型值取16 或32)。为了进行路由,Pastry 把nodeId 和关键字表示为一串以2b 为基的数,查询消息被路由到nodeId和关键字在数值上最接近的节点。方法是:每个节点把查询消息转发给下一个节点时,要保证这个节点的nodeId 和关键字的相同前缀至少要比当前节点的nodeId 和关键字的相同前缀长一个数位(即b 个比特)。如果找不到这样的邻居节点,消息将转发给前缀长度相同但是节点号数值更接近关键字的节点。为此,每个Pastry 节点都需要维护状态表:一张路由表,一个邻居节点集和一个叶子节点集。


图2 Pastry节点维护的数据示意图

       图 2 给出了一个节点维护的数据示意图,b 取值为2,所有的数均是4 进制的。其中路由表的最上面一行是第0 行。路由表每行包括2b-1 个表项,第n 行的2b-1 个表项中,每个节点nodeId 的前n 个数位和当前节点nodeId 的前n 个数位相同,而第n+1 个数位和当前节点不同。b 的取值是路由表大小和任意两节点间需要的最大路由跳数之间的折衷。叶子节点集维护的是nodeId 和本节点最接近的节点,其中一半是nodeId 大于当前节点的,另一半是nodeId 小于当前节点的。叶子节点集在路由时需要用到。通常这两个集合的大小分别为2b 或者2×2b。

3.2 Pastry 的路由
      Pastry 的路由过程是:节点收到一条查询消息时,首先检查该消息的关键字是否落在叶子节点集范围内。如果是,则直接把消息转发给对应的节点,也就是叶子节点集中nodeId和关键字最接近的节点。如果关键字没有落在叶子节点集范围内,节点就会把消息转发给路由表中的一个节点,该节点的nodeId 和关键字的相同前缀至少要比当前节点的nodeId 和关键字的相同前缀长一个数位。如果路由表中相应的表项为空,或者表项中对应的节点不可达,这时候查询消息将被转发给前缀长度相同但是节点号数值更接近关键字的节点。

3.3 节点的加入和退出
      新节点加入时需要初始化自身的状态表,并通知其他节点自己已经加入系统。假定新加入节点的nodeId 为X,同时假定X 在加入Pastry 之前知道系统中和自己距离相近的节点A。新节点X 首先请求A 路由一条“加入”消息,消息的关键字就是X。这条消息最终会到达nodeId和X 最接近的节点Z。从交换的消息数量上说,节点加入操作的复杂度为O(log
2bN)。Pastry 中节点很可能失效或者突然离开系统。一旦节点检测出其叶子节点集L 中的某个节点失效,它就会请求该集合中nodeId 最大或最小的节点把其叶子节点集L’发送过来。当前节点将从L’中选择一个L 中没有的活动节点来替代失效节点。如果节点检测出其路由表中某项对应的节点失效,它将从该项所在的路由表行中选择另一个节点,要求该节点把路由表中对应位置的项发过来。

4. Tapestry
4.1 Tapestry 原理
      Tapestry 从一个标识符空间中为每个节点随机分配一个节点标识符nodeID,对象也从同一个标识符空间中分配一个全局唯一标识符GUID。为了讨论问题的方便,用Nid 来表示节点N 的标识符,用OG 表示对象O 的标识符。Tapestry 目前使用160 比特的标识符空间,标识符用一个全局统一的进制表示,所有的节点依据标识符自组织成一个重叠网络。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”为前缀而且离当前节点最近的邻居节点。


图 3 给出了一个节点的邻居指针实例,从图中可以看到第一级的邻居节点标识和本节点标识没有共同前缀,而第二级的邻居节点标识都以4 开头,即和本节点标识具有相同的一个数位的前缀。

4.2 Tapestry 的路由
      Tapestry 采用的基本查找和路由机制:当一条查找消息到达传递过程中的第n 个节点时,该节点和目的节点的共同前缀长度至少大于n。为了进行转发,该节点将查找邻居映射表的第n+1 级中和目的标识符下一数位相匹配的邻居节点。转发过程将在每个节点中依次进行直到到达目的节点。
      Tapestry 中的节点在共享数据时被称为服务器,请求数据时被称为客户,转发消息时被称为路由器。也就是说每个节点可以同时具有客户、服务器和路由器的功能。 服务器S通过向对象O(GUID 为OG)的根节点OR 定期的发送消息来报告S 保存有对象O。在这条发布路径上的每个节点都保存关于这个对象O 的位置信息指针<OG, S>,这里的位置信息只是一个指向S 的指针,而并不是对象O 的拷贝。当多个都存有同一对象拷贝的服务器分别向根结点发布消息时,路径上的每个节点按各个服务器离自己的网络时延递增的顺序保存这些位置指针列表。

4.3 节点的加入和退出
      Tapestry 的节点加入算法和Pastry 类似。节点N 在加入Tapestry 网络之前,也需要知道一个已经在网络中的节点G。然后N 通过G 发出路由自己的节点ID 的请求,根据经过的节点的对应的邻居节点表构造自己的邻居节点表。构造过程中还需要进行一些优化工作。构造完自己的数据结构后,节点N 将通知网络中的其他节点自己已经加入网络。通知只针对在N 的邻居映射表中的主邻居节点和二级邻居节点进行。 Tapestry 采用两种机制处理节点的退出。一种情况是节点从网络中自行消失(主要原因是节点失效),在这种情况下,它的邻居可以检测到它已经退出网络并可以相应的调整路由表。另一种机制是节点在退出系统之前通过后向指针通过所有把它作为邻居的节点,这些节点会相应调整路由表并通知对象服务器该节点已经退出网络。检测正常操作过程中的链路和服务器失效,可以使用TCP 连接超时
机制。

5. CAN
5.1 CAN 原理
      CAN 的设计基于虚拟的d 维笛卡儿坐标空间,这个坐标空间完全是逻辑的,和任何物理坐标系统都没有关系。在任何时候,整个坐标空间动态地分配给系统中的所有节点,每个节点负责维护独立的互不相交的一块区域。CAN 中的节点自组织成一个代表这个虚拟坐标空间的重叠网络(overlay network)。每个节点要了解并维护相邻区域中节点的IP 地址,用这些邻居信息构成自身的坐标路由表。有了这张表,CAN 可以在坐标空间中任意两点间进行寻路。


图4 CAN节点空间示意

      图4 给出了一个2 维的[0, 1]×[0, 1]的笛卡儿坐标空间划分成五个节点区域的情况。虚拟坐标空间采用下面的方法保存(K, V)对。当保存(K1, V1)时,使用统一的哈希函数把关键字K1 映射成坐标空间中的点P。那么这个值将被保存在该点所在区域的节点中。当需要查询关键字K1 对应的值时,任何节点都可以使用同样的哈希函数找到K1 对应的点P,然后从该点对应的节点取出相应的值V1。如果此节点不是发起查询请求的节点,CAN 将负责将此查询请求转发到P 所在区域的节点上。因此,有效的路由机制是CAN 中的一个关键问题。

5.2 CAN 的路由
      CAN 中的路由很简单,沿着坐标空间中从发起请求的点到目的点之间的一条路径转发即可。为此,每个CAN 节点都要保存一张坐标路由表,其中包括它的邻居节点的IP 地址和其维护的虚拟坐标区域。两个节点互为邻居是指:在d 维坐标空间中,两个节点维护的区域在d-1 维的坐标上有重叠而在剩下的一维坐标上相互邻接。每条CAN 消息都包括目的点坐标。路由时节点只要朝着目标节点的方向把消息转发给自己的邻居节点即可。

      如果一个d 维空间划分成n 个相等的区域,那么平均路由长度是(d/4)(n1/d),每个节点只需要维护2d 个邻居节点的信息。这个结果表明CAN 的可扩展性很好,节点数增加时每个节点维护的状态信息不变,而路由长度只是以O(n1/d)的数量级增长。因为坐标空间中两点之间可以有许多条不同的路径,所以单个节点的失效对CAN 基本上没有太大的影响。遇到失效节点时,CAN 会自动沿着其他的路径进行路由。

5.3 节点加入和退出
      因为整个CAN 空间要分配给系统中现有的全部节点,当一个新的节点加入网络时必须得到自己的一块坐标空间。CAN 通过分割现有的节点区域实现这一过程。它把某个现有节点的区域分裂成同样大小的两块,自己保留其中的一块而另一块分给新加入的节点。
      当节点离开CAN 时,必须保证它的区域被系统中剩余的节点接管,也即分配给其他仍然在系统中的节点。一般是由某个邻居节点来接管这个区域和所有的索引数据(K,V)对。如果某个邻居节点负责的区域可以和离开节点负责的区域合并形成一个大的区域,那么将由这个邻居节点执行合并操作。否则,该区域将交给其邻居节点中区域最小的节点负责。也就是说,这个节点将临时负责两个区域。

6.上述路由算法的比较和分析

      以上介绍了四种用于对等网络的查找系统,从中可以看出,它们具有很多相似的特点,比如都采用了SHA-1 哈希函数来获得标识符,都采用了通过路由表机制进行路由转发,在处理结点的加入和退出时都采取了相似的步骤,等等。基于这些系统,研究人员还设计了改进的路由机制具有更好的性能


      有些研究人员己经认识到基于结构化分布式哈希表的路由机制也有无法解决的问题。首先,经过哈希之后,结点的位置信息被破坏了,来自同一个子网的站点很可能结点号相距甚远,这不利于查询性能的优化。其次,基于哈希表的系统不能利用应用本身的信息,许多应用(比如文件系统)的数据本身是按照层次结构组织的,而使用哈希函数后,这些层次信息就丢失了。

7. 结论
路由查找效率,Chord, Tapestry 算法复杂度都为O (logn), CAN 为dn1/d, Pastry 为O(nlogn)。Pastry 考虑了网络的物理拓扑,Pastry 的路由路线将尽量选择最佳路径,减小消息的传送时间。Pastry 的这一特性称为网络拓扑相关性。Chord 和CAN 在这方面都没有考虑物理网络的距离。Tapstry 采用较优的根冗余策略,但其路由时动态构建不彻底,路由相对来说较容易失败。在这几个系统中,Chord 的负载均衡做的较好,它采用虚拟服务器技术,根据节点能力的不同所创建的虚拟节点的个数也就不同,但是也增加了Chord 的路由延迟。


-------------------------------转载自北京邮电大学电信工程学院周巍











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值