在torrent kademlia路由表

时间:2015-06-04 21:22:31

标签: routing bittorrent dht kademlia

我已经审阅了很多关于这个主题的文件,但有些内容并不完全清楚。例如,比特种子文档(http://www.bittorrent.org/beps/bep_0005.html)状态

  

路由表细分为"桶"每个覆盖一个   部分空间。空表有一个带有ID空间的存储桶   范围min = 0,max = 2 ^ 160。当ID为" N"的节点时被插入   表,它被放置在具有min< = N<最大。一个   空表只有一个桶,因此任何节点都必须适合它。每   在成为" full之前,bucket只能容纳K个节点,目前为8个节点。   当存储桶中充满已知的良好节点时,不能再添加节点   除非我们自己的节点ID落在桶的范围内。在那里面   例如,铲斗由两个新铲斗替换,每个铲斗有一半   旧桶的范围和旧桶的节点是   分布在两个新的。对于只有一个的新表   水桶,满桶总是分成两个新的水桶覆盖   范围0..2 ^ 159和2 ^ 159..2 ^ 160。

与kademlia路由表的其他文档有些不同,其中桶根据节点id的位前缀排列,但还有另一个令人困惑的事情。当我们回复"找到节点"请求我们必须使用XOR操作找到8个最近的节点到请求的节点。我看到一些实现只是遍历路由表中的每个项目执行XOR操作,从而找到8个最接近的项目。在我看来,CPU太浪费了。

一切都在桶里。即使我们使用bit torrent文件系统的建议,我们也可以更快地找到可能包含所请求的节点id的存储桶,只需枚举存储桶并检查其上的最小和最大数量。那么潜在的那个桶应该包含关闭的节点,但它们是最接近的节点而不是XOR最接近的节点(据我所知),这有点不同但有些相似。

我使用0到99之间的数字进行了一个简单的测试,我想找到8个XOR最接近的数字,它们位于所寻找的数字附近,但不在它附近。现在,考虑一下我们的存储桶,我想有可能存储桶中的所有节点ID都是最小的异常。因此,例如,如果我们采用这个桶,从左边拿一个,从右边拿一个,并搜索最近的XOR节点ID,我们将找到我们正在寻找的东西,没有必要通过所有节点路由表。

我是对的还是我错过了什么?

1 个答案:

答案 0 :(得分:4)

  

与kademlia路由表的其他文档有些不同,其中桶根据节点id的位前缀排列,但还有另一个令人困惑的事情。

bittorrent规范描述了一种路由表实现,它只是近似kademlia paper中描述的那种。它更容易实现,但有一些缺点。

  

所以,例如,如果我们拿这个桶,从左边拿一个,从右边拿一个,找到最近的XOR节点id,我们找到我们正在寻找的东西,没有必要经过路由表中的所有节点。

在两者中 - 完整的,树状路由表实现和简化的BEP5变体 - 每个桶可以被认为具有CIDR-like prefix(参见this SO answer),其由前缀位组成,桶盖和面罩钻头数。

在BEP5变体中,每个存储桶的前缀只是从数组索引和节点自己的ID中派生出来的。在树状表中,由于存储桶拆分/合并操作,存储桶必须跟踪其前缀。

使用这些前缀,您可以找到覆盖目标密钥的存储桶。

问题是水桶不必是满的,如果你想发送,让我们说一个响应中的20个节点就不够了。

因此,您必须遍历路由表(根据您自己的节点ID或自然距离排序),以相对于目标密钥的上升距离(XOR)顺序来访问多个存储桶。

由于XOR距离度量在每个位进位(XOR ==无进位加法)处折叠,因此它不能很好地映射到任何路由表布局。换句话说,访问最近的水桶不会。

Here's my implementation用于从树状路由表中查找到特定目标密钥的N个最近节点。

我认为很多人只是遍历整个路由表,因为对于常规节点,它最多只包含几十个桶,DHT节点看不到很多流量,所以它只需执行几次这个操作每秒如果你在一个密集的,缓存友好的数据结构中实现它,那么狮子的份额实际上可能是内存流量,而不是CPU指令进行一些XOR和比较。

即。全表扫描很容易实现。

假设我们有一个路由表,每个桶都有以下位前缀。这些字母就像方便的名字一样。)

A 000... 
B 00100... 
C 0010100... 
D 0010101000... 
E 0010101001...
F 001010101... 
G 00101011... 
H 001011... 
I 0011... 
J 01... 
K 1... 

现在让我们说我们正在寻找这个目标密钥:

T = 0010011010111111001111100101011000001010010100001100100010011100000000100100000111001101100110110110101100010100111010111001101111110101001001001000100000001001

此外,水桶不是完全装满的,或者我们需要的输入数量多于装入单个水桶的数量,因此我们必须访问多个水桶才能获得所需的数量。

现在,第一个要访问的存储桶相当明显,它的B因为它的前缀涵盖了目标密钥。

由于B的前缀长度为5位,因此该存储区中的任何条目都与T 00000???????...的XOR距离。共享5个前缀位。

B是距T最近的存储桶,这意味着不能有任何比相对距离00000...更近的路由表条目。相反,这意味着B之外的任何条目可以具有的最小距离为00001...。这意味着下一个最接近的存储桶必须覆盖T xor 00001... -> 00101110101111110[...]

涵盖此内容的存储区为H

HB

不相邻

最终 - 假设我们必须访问6个桶 - 订单将如下所示:

00100...      -> B
001011...     -> H
001010101...  -> F
0010101000... -> D
0010101001... -> E
00101011...   -> G

这看起来相当混乱。但是,如果我们为每个访问过的桶绘制前缀到目标密钥的距离,那么它就变得更加明显了:

00000...
000010...
000011000...
0000110010...
0000110011...
00001101...

所以算法如下:

  1. 找到覆盖目标密钥的初始存储桶
  2. 使用目标密钥(零掩码尾随位)对存储桶的前缀进行异或(
  3. 通过该前缀的最低位
  4. 增加距离
  5. XOR使用目标键增加距离
  6. 找到覆盖XORed键的下一个桶
  7. 转到2
  8. TL; DR:"只看一个桶左,一个桶右边#34;还不够。正确的算法是相当复杂的,整个表格的线性扫描更容易实现。