我已经审阅了很多关于这个主题的文件,但有些内容并不完全清楚。例如,比特种子文档(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,我们将找到我们正在寻找的东西,没有必要通过所有节点路由表。
我是对的还是我错过了什么?
答案 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
。
H
与B
最终 - 假设我们必须访问6个桶 - 订单将如下所示:
00100... -> B
001011... -> H
001010101... -> F
0010101000... -> D
0010101001... -> E
00101011... -> G
这看起来相当混乱。但是,如果我们为每个访问过的桶绘制前缀到目标密钥的距离,那么它就变得更加明显了:
00000...
000010...
000011000...
0000110010...
0000110011...
00001101...
所以算法如下:
TL; DR:"只看一个桶左,一个桶右边#34;还不够。正确的算法是相当复杂的,整个表格的线性扫描更容易实现。