分布式下载方式(二)DHT分布式网络

简单回顾以下上一篇文章介绍了内容:分布式下载方式(一)原理分析

分布式下载方式也有两种:依赖tracker的“元数据集中,文件数据分散”的方式;另一种是基于分布式的哈希算法,保证元数据和文件数据完全分开。

在 DHT 网络里面,每一个 DHT node 都有一个 ID。这个 ID 是一个很长的串。每个 DHT node 都有责任掌握一些知识,也就是文件索引,或者叫做文件Hash值。每一个DHT node都有一个ID,这个ID是一个160bits(20字节)的数据,它存储的文件标识也是一个160bits的Hash值。

上面文章我们也介绍了在DHT网络中我们知道需要联系的节点,但是有时候不一定能找到这个节点,但是也可以退而求其次,找到与其相似的节点,那么这个“相似”怎么定义?相似不是地理位置的接近,位置近不算近,ID相近或者相似才是近。这个相似的比较通过异或XOR来处理。举个例子,两个节点01010 与 01000 的距离,就是两个 ID 之间的异或值,为 00010,也即为 2。01010 与 00010 的距离为 01000,也即为 8,。01010 与 00011 的距离为 01001,也即 8+1=9 。以此类推,高位不同的,表示距离更远一些;低位不同的,表示距离更近一些,总的距离为所有的不同位的距离之和。

如何维护DHT网络节点

DHT网络中有很多节点,就像人的朋友圈网络一样。朋友圈中的朋友关系有远近之分,当然DHT中节点之间的关系也有远近之分,上面也讲了如何判断两个节点是否相近(或者叫相似)。

DHT网络的节点是按照层次来划分的,举个例子就清楚了。

假设某个节点的 ID 为 01010,如果一个节点的 ID,前面所有位数都与它相同,只有最后 1 位不同。这样的节点只有 1 个,为 01011。与基础节点的异或值为 00001,即距离为 1;对于 01010 而言,这样的节点归为“k-bucket 1”。

如果一个节点的 ID,前面所有位数都相同,从倒数第 2 位开始不同,这样的节点只有 2 个,即 01000 和 01001,与基础节点的异或值为 00010 和 00011,即距离范围为 2 和 3;对于 01010 而言,这样的节点归为“k-bucket 2”。我们上面也说了,高位不同的,表示距离更远一些;低位不同的,表示距离更近一些。

如果一个节点的 ID,前面所有位数相同,从倒数第 i 位开始不同,这样的节点只有 2^(i-1) 个,与基础节点的距离范围为[2^(i-1), 2^i);对于 01010 而言,这样的节点归为“k-bucket i”。

最终到从倒数 160 位就开始都不同。

你会发现,差距越大,陌生人越多,但是朋友圈不能都放下,所以每一层你可以放N个节点,N要在一定的范围之内即可。这就是DHT网络分层的由来。

通过这样的分层,我们可以将DHT中各个节点之间的远近关系建立起来,这样在查找的时候很清晰。那么问题来了,DHT网络如何查找节点?

DHT网络如何查找节点

在DHT网络分层的基础上,我们来查找节点,还是举例子清晰表达一下。

假设,node A 的 ID 为 00110,要找 node B ID 为 10000,异或距离为 10110,距离范围在[2^4, 2^5),所以这个目标节点可能在“k-bucket 5”中,这就说明 B 的 ID 与 A 的 ID 从第 5 位开始不同,所以 B 可能在“k-bucket 5”中。

然后,A 看看自己的 k-bucket 5 有没有 B。如果有,太好了,找到你了;如果没有,在 k-bucket 5 里随便找一个 C。因为是二进制,C、B 都和 A 的第 5 位不同,那么 C 的 ID 第 5 位肯定与 B 相同,即它与 B 的距离会小于 2^4,相当于比 A、B 之间的距离缩短了一半以上。

再请求 C,在它自己的通讯录里,按同样的查找方式找一下 B。如果 C 知道 B,就告诉 A;如果 C 也不知道 B,那 C 按同样的搜索方法,可以在自己的通讯录里找到一个离 B 更近的 D 朋友(D、B 之间距离小于 2^3),把 D 推荐给 A,A 请求 D 进行下一步查找。

Kademlia 的这种查询机制,是通过折半查找的方式来收缩范围,对于总的节点数目为 N,最多只需要查询 log2(N) 次,就能够找到。

 

上面的图示就是最坏的一种情况,即使这样,也还是很快。

A 和 B 每一位都不一样,所以相差 31,A 找到的朋友 C,不巧正好在中间。和 A 的距离是 16,和 B 距离为 15,于是 C 去自己朋友圈找的时候,不巧找到 D,正好又在中间,距离 C 为 8,距离 B 为 7。于是 D 去自己朋友圈找的时候,不巧找到 E,正好又在中间,距离 D 为 4,距离 B 为 3,E 在朋友圈找到 F,距离 E 为 2,距离 B 为 1,最终在 F 的朋友圈距离 1 的地方找到 B。当然这是最最不巧的情况,每次找到的朋友都不远不近,正好在中间。

如果碰巧了,在 A 的朋友圈里面有 G,距离 B 只有 3,然后在 G 的朋友圈里面一下子就找到了 B,两次就找到了。

查找到了节点,那么如何沟通?

DHT网络中节点如何沟通?

Kademlia 算法中,每个节点只有 4 个指令:

  • PING:测试一个节点是否在线,还活着没,相当于打个电话,看还能打通不。
  • STORE:要求一个节点存储一份数据,既然加入了组织,有义务保存一份数据。
  • FIND_NODE:根据节点 ID 查找一个节点,就是给一个 160 位的 ID,通过上面朋友圈的方式找到那个节点。
  • FIND_VALUE:根据 KEY 查找一个数据,实则上跟 FIND_NODE 非常类似。KEY 就是文件对应的 160 位的 ID,就是要找到保存了文件的节点。

DHT之所以是一个高效的分布式网络,说明它是一个动态更新的网络,网络节点之间的远近是动态更新的,如何更新节点信息?

  • 每个 bucket 里的节点,都按最后一次接触的时间倒序排列,这就相当于,朋友圈里面最近联系过的人往往是最熟的。
  • 每次执行四个指令中的任意一个都会触发更新。
  • 当一个节点与自己接触时,检查它是否已经在 k-bucket 中,也就是说是否已经在朋友圈。如果在,那么将它挪到 k-bucket 列表的最底,也就是最新的位置,刚联系过,就置顶一下,方便以后多联系;如果不在,新的联系人要不要加到通讯录里面呢?假设通讯录已满的情况,PING 一下列表最上面,也即最旧的一个节点。如果 PING 通了,将旧节点挪到列表最底,并丢弃新节点,老朋友还是留一下;如果 PING 不通,删除旧节点,并将新节点加入列表,这人联系不上了,删了吧。

一个优秀的分布式网络,任何节点的加入和离开都不会随便影响整体网络的稳定性,这样才是一个健壮的分布式网络。

小结

  • DHT采用异或来区分远近,高位不同的,表示距离更远一些;低位不同的,表示距离更近一些。
  • DHT采用分层的方式将远近关系层次化。
  • DHT层次的划分依据,是方便查找节点。最快的利用层次关系来查找节点,查询的效率是log2(N)
  • DHT更新节点的原则基本上遵照着LRU的方式。

知道了分布式下载方式的基本原理,接下来了需要一些实践,如何搭建一个分布式下载的架构来承载分布式下载的业务。请继续关注,稍后会分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章