Skip to content

Latest commit

 

History

History
132 lines (81 loc) · 10.4 KB

File metadata and controls

132 lines (81 loc) · 10.4 KB

结构化网络

混合式网络对其中的超级节点还是有一定的依赖性,相当于超级节点之间组成了一种集中式的网络,依赖超级节点的节点组成了星形网络,而对外网络整体表现为分布式网络。普通节点依赖特定的超级节点组织就会出现问题,或者更抽象一下,只要一部分节点依赖另一部分节点组织网络,就相当于放弃了自己组织网络的权利,让渡到其他节点来帮助网络的建立。

这个时候我们需要建立一种规则,组织网络的权利不用在节点间让步,而是一种更高层的规则,这个规则与节点并无厉害关系,是一种中立的存在,存在的意义只是为了帮助节点建立网络。这个时候,就可以设计一种结构化的P2P网络来达成我们的目的。

结构化P2P网络也是一种分布式网络结构,但又与纯分布式有所区别。纯分布式网络就是一个随机网络,而结构化网络则将所有节点按照某种结构有序的组织起来,比如形成一个环状网络或者树状的网络。

结构化网络的具体实现上普遍都是基于DHT(Distributed Hash Table,分布式哈希表) 算法。具体的实现方案有 Chord、Pastry、CAN、Kademlia 等算法,其中 Kademlia 也是以太坊网络的实现算法。

Kad算法原理

Kademlia(简称kad)算法是一种通过分散式杂凑表实现的协议算法,由Petar和David在2002年为P2P网络设计的一种结构化网络模型,用来在分布式环境中准确的路由,定位数据。在Kad网络中每个节点都有一个随机产生的160bit的标识符作为节点ID,节点通过计算与目标节点ID间的距离来快速路由和定位资源。Kad算法通过异或节点ID来计算节点之间的距离,这个距离是逻辑上的距离并不是节点间物理上的距离,逻辑距离近的节点不一定在物理距离上也近。下面是一个计算节点间距离的例子:

节点A的ID(010)
节点B的ID(110)
A ⊕ B = 100(二进制) = 4(十进制)

在Kad算法中需要根据节点ID从高到低映射为一个二叉树,然后每个节点按照一定规则对二叉树进行拆分,以便快速路由。二叉树的映射规则如下:

  • 将节点ID(160bit)从高到低依次分层,第N位就对应了第N层;
  • 如果是0进入左子树,如果是1则进入右子树;
  • 每个节点就对应树中的一个叶子;

将节点映射为二叉树后就需要每一个节点从自己的视角将二叉树进行拆分,拆分规则是从根节点开始,把不包含自己的子树拆分出来,然后在剩下的子树再拆分不包含自己的下一层子树,以此类推,直到最后只剩下自己。下图的例子就是以节点ID为110的视角多二叉树进行了拆分:

在拆分后需要保证自己至少存储每个子树中的1个节点,这对于节点路由非常重要。在进行拆分后对于一个具有2的n次方节点的Kad网络在最坏的情况下只需要n步就可以找到被搜索节点。

查找过程:

假设节点110作为发起节点想快速找到节点010,此时节点110存储了子树1的000节点,子树2的100节点,子树3的111节点。

与搜索目标的距离 110 xor 010 = 100 = 4(十进制) 与搜索子树1节点000的距离 110 xor 000 = 110 = 6(十进制) 与搜索子树2节点100的距离 110 xor 100 = 010 = 2(十进制) 与搜索子树3节点111的距离 110 xor 111 = 001 = 1(十进制)

为了找到目标节点,首先需要缩短与目标节点的距离,所以先查询子树2的节点100。

同样节点100也会按自己的视角拆分子树,得到如下所示

此时可以看做节点节点100作为发起节点想快速找到节点010,此时节点110知道子树1的000节点,子树2的100节点,子树3的111节点。

与搜索目标的距离 100 xor 010 = 110 = 6(十进制) 与搜索子树1节点000的距离 100 xor 000 = 011 = 3(十进制) 与搜索子树2节点101的距离 100 xor 101 = 001 = 1(十进制) 与搜索子树3节点110的距离 100 xor 110 = 010 = 2(十进制)

为了找到目标节点,首先需要缩短与目标节点的距离,所以先查询子树1的节点000。

同样节点000也会按自己的视角拆分子树,得到如下所示

而节点000存储了目标节点010,至此整个递归查询的过程就完成了。

因为Kad算法默认的节点ID是160bit,所有拆分以后最多可以有160课子树,而对于每个子树,如果我们分别知道里面的一个节点,就可以利用这个节点递归路由到子树的任意一个节点。但是在实际应用中,由于节点是动态增加减少的,如果知道的节点恰好宕机或者下线了就会出现问题,为了保证系统的鲁棒性Kad算法又引入了K桶(K-bucket)的机制。

K桶(k-bucket

节点在完成拆分子树以后需要记录每个子树里面K个节点,由于每个K桶覆盖距离的范围呈指数关系增长,这就形成了离自己近的节点的信息多,离自己远的节点的信息少,从而可以保证路由查询过程是收敛。而这个K可以由用户自己定义,在BT下载使用的Kad算法中K是8。

K-bucket实际上就是路由表,每个节点按照自己的视角拆分完子树以后可以得到N个子树,那就需要维护N个路由表,对应N个K-bucket.

每个节点维护N个K-bucket以后还会出现一个问题,在Kad网络中的节点会动态的增加或者减少,对应到具体的数据结构里就表现为K-bucket中节点数据的动态增减,为了保证k-bucket中保存节点数据的有效性就需要对其进行更新。

K桶的更新机制

K-bucket主要有三种方式来更新路由表。

  • 主动收集节点,主动发起FIND_NODE查询节点的请求,从而更新K桶的节点信息。
  • 被动收集节点,当收到其他节点发送过来的请求(如:FIND_NODE、FIND_VALUE),会把对方的节点ID加入到某个K桶中。
  • 检测失效节点,周期性的发起PING请求,判断K桶中某个节点是否在线,然后清理K桶中哪些下线的节点。

当节点收到其它节点foo发来的请求(FIND_NODE、FIND_VALUE)时,需要用foo的ID来更新自己的K桶,更新步骤如下:

  • 计算自己和目标节点ID的距离d。
  • 通过距离d找到对应的K桶,如果ID已经在K桶中了则把对应项移到K桶的末尾。
  • 如果不在K桶中则有两种情况。 1.如果该K桶存储的节点小于K个,则直接把目标节点插入到K-桶尾部; 2.如果该K桶存储节点大于等于K个,则选择K-桶中的头部节点进行PING操作,检测节点是否存活。如果头部节点没有响应,则移除该头部节点,并将目标节点插入到队列尾部;如果头部节点有响应,则把头部节点移到队列尾部,同时忽略目标节点。

通过这种更新策略可以保证在线时间长的节点有较大的可能继续保存在K桶中,降低了稳定网络构建路由表的成本。

加入Kad网络

当一个新节点需要加入Kad网络时,需要通过如下的步骤:

  • 新节点A需要一个种子节点B作为引导,并把该种子节点加入到K桶中。
  • 生成一个随机的节点ID,直到离开网络一直使用。
  • 向节点B发送FIND_NODE请求。
  • 节点B在收到节点A的FIND_NODE请求后,会根据FIND_NODE请求的约定,找到K个距离A最近的节点,并返回给A节点
  • A收到这些节点以后,就把它们加入到自己的K桶中
  • 然后节点A会继续向这些刚拿到节点发起FIND_NODE请求,如此往复,直到A建立了足够详细的路由表。

定位节点

节点查询可以同步进行也可以异步进行,同时查询并发一般为3。

  • 确定目标ID对应路由表中的K桶位置,然后从自己的K-桶中筛选出K个距离目标ID最近的节点,并同时向这些节点发起FIND_NODE的查询请求。
  • 被查询节点收到FIND_NODE请求后,从对应的K桶中找出自己所知道的最近的K个节点,并返回给发起者。
  • 发起者在收到这些节点后,更新自己的结果列表,并再次从其中K个距离目标节点ID最近的节点,挑选未发送请求的节点重复第一步
  • 不断重复上面的步骤直到找到目标节点为止

当有消息需要广播的整个P2P网络的时候,只需要将消息告诉相邻节点即可,然后层层广播至整个网络,当需要与指定节点通信时,可以不断的缩短与目标节点的距离,很快就可以找到目标节点,需要注意的是这种查找速度并不会随着节点的增多而增加。

这种组织形式的网络,整体的鲁棒性非常强大,当网络中的部分节点遭受攻击或者出现故障不能及时恢复的时候,其余节点可以绕过这些节点,重新组织网络,使网络得到恢复的,非常适用于区块链的场景。

以太坊中的KAD网络

以太坊采用的就是Kademlia分布式哈希表来组织节点。

节点ID

以太坊中的每一个节点都有一个Secp256k1生成的ID,节点的公钥作为标识节点的ID,节点间的距离是公钥哈希按位异或得到的。

distance(N1,N2) = keccak256(N1) XOR keccak256(N2)

节点列表

节点列表,节点列表用以在节点发现协议中保存相邻节点信息,相邻节点的信息被包含在一个称为K桶的路由表中,路由表可以保存16个节点条目,其中按时间排序,越新发现的节点越靠前。当一个新节点N1被发现,就可以加入到桶中,如果桶中少于16个节点则可以加入到桶的第一位,如果桶满了则需要从桶的最后一位开始ping检测,如果有下线的节点则移除后再添加新节点,如果桶中的节点都在线则把这个节点加入备份列表。