标签:数据 span bucket 排除 存储过程 移除 防御 下载 .com
在上一篇文章中《P2P技术是什么》,我们介绍了P2P技术的特点以及发展历史。在本篇文章中,我们来介绍某一个具体的算法。
如今很多P2P网络的实现都采用DHT的方式实现查找,其中Kademlia(简称Kad)算法由于其简单性、灵活性、安全性成为主流的实现方式。下面我们就来详细分析这个应用于比特币和以太坊P2P网络中的Kad算法。
声明:原创文章,转载请备注来源: https://shuwoom.com/?p=813
Kad网络中每个节点都有一个160bit的ID值作为标志符,Key也是一个160bit的标志符,每一个加入Kad网络的节点都会被分配一个160bit的节点ID(node ID),这个ID值是随机产生的。同时<key, value>对的数据就存放在ID值距离key值最近的若干个节点上。
Kad算法一个精妙之处在于它采用异或操作来计算节点之间的距离。通过异或操作,我们可以得到该距离算法有一下特点:
所以,这里所说的距离是逻辑上的距离,与地理位置无关,所以有可能两个节点之间计算得到的逻辑距离很近,但实际上地理上的距离却很远。
例如:节点A的ID(011)和节点B的ID(101)距离:011 ⊕ 101 = 110 = 4+2 = 6。
当我们把所有节点ID都按照上述步骤操作后,会发现,这些节点形成一颗二叉树。
节点110的视角
每一个节点都可以从自己的视角来对二叉树进行拆分。
拆分规则是从根节点开始,把不包含自己的子树拆分出来,然后在剩下的子树再拆分不包含自己的下一层子树,以此类推,直到最后只剩下自己。如上图所示,以节点ID为6(110)为视角进行拆分,可以得到3个子树(灰色圆圈)。而以节点101为视角拆分,则可以得到如下二叉树。
节点101的视角
Kad默认的散列值空间是m=160(散列值有160bit),所以拆分以后的子树最多有160个。而考虑到实际网络中节点个数远远没有2^160个,所以子树的个数明显小于160个。
对于每个节点,当按照自己的视角对二叉树进行拆分以后,会得到n个子树。对于每个子树,如果都分别知道里面1个节点,那么就可以利用这n个节点进行递归路由,从而可以达到整个二叉树的任何一个节点。
假设每个节点ID是N bits。每个节点按照自己视角拆分完子树后,一共可以得到N个子树。上面说了,只要知道每个子树里的一个节点就可以实现所有节点的遍历。但是,在实际使用过程中,考虑到健壮性(每个节点可能推出或者宕机),只知道一个节点是不够的,需要之多多几个节点才比较保险。
所以,在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-桶中存放的位置是根据上次看到的时间顺序排列,最早访问的放在头部,最新访问的放在尾部。
主要有以下3种
任何节点都可以发起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节点的加入。
标签:数据 span bucket 排除 存储过程 移除 防御 下载 .com
原文地址:https://www.cnblogs.com/vana/p/9977626.html