【问题标题】:Implementing find node on torrent kademlia routing table在 torrent kademlia 路由表上实现查找节点
【发布时间】:2017-10-19 05:46:59
【问题描述】:

我已经查看了有关此主题的许多文档,但有些内容并不完全清楚。例如 bit torrent 文档 (http://www.bittorrent.org/beps/bep_0005.html) 状态

路由表被细分为“桶”,每个桶覆盖一个 空间的一部分。一个空表有一个带有 ID 空间的桶 最小值=0,最大值=2^160的范围。当一个 ID 为“N”的节点被插入到 表,它被放置在具有 min

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

一切都已经在存储桶中。即使我们使用 bit torrent 文档系统建议的方法,我们也可以更快地找到可能包含请求的节点 ID 的存储桶,只需枚举存储桶并检查其上的最小和最大数量。然后可能该存储桶应该包含关闭节点,但它们是值最接近的节点而不是 XOR 最接近的节点(据我了解),这有些不同但有些相似。

我使用从 0 到 99 的数字运行了一个简单的测试,我想在其中找到 8 个 XOR 最接近的数字,它们在所寻找的数字附近但不在它附近。现在,考虑到我们的存储桶,我猜可能存储桶中的所有节点 id 都是最接近的一个小异常。因此,例如,如果我们拿这个桶,从左边取一个,从右边取一个,并搜索 XOR 最接近的节点 ID,我们将找到我们正在寻找的内容,并且没有必要遍历路由中的所有节点表。

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

【问题讨论】:

  • 经过一些测试,我发现我之前的答案实际上是不正确的,更新它以反映正确且经过测试的算法。

标签: routing bittorrent dht kademlia


【解决方案1】:

它与其他关于kademlia路由表的文档有些不同,其中bucket是根据节点id的位前缀排列的,但还有一个令人困惑的地方。

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

因此,例如,如果我们拿这个桶,从左边取一个,从右边取一个,并搜索 XOR 最接近的节点 ID,我们会找到我们正在寻找的东西,没有必要遍历所有节点在路由表中。

在这两种情况下——完整的树状路由表实现和简化的 BEP5 变体——每个桶都可以被认为有一个 CIDR-like prefix(参见 this SO answer),由桶覆盖的前缀位和一个掩码位数。

在 BEP5 变体中,每个存储桶的前缀都简单地从数组索引和您的节点自己的 ID 派生而来。在树状表中,由于桶拆分/合并操作,桶必须跟踪它们的前缀。

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

问题是桶不一定是满的,如果你想发送,假设一个响应中有 20 个节点一个桶是不够的。

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

由于 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???????... 有异或距离。 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...

所以算法如下:

  1. 找到覆盖目标键的初始存储桶
  2. 存储桶的前缀与目标键异或(零掩码尾随位)
  3. 将距离增加该前缀的最低有效位
  4. 与目标键异或增加距离
  5. 找到下一个覆盖 XORed 键的存储桶
  6. 转到 2

TL;DR:“只看左边一桶,右边一桶”是不够的。正确的算法相当复杂,整个表的线性扫描更容易实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-14
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多