Kademlia协议(模型)是被电驴,BitTorrent所采用了的,基于异或距离算法的分布式散列表(DHT), 它实现了一个去中心化的信息储存与查询系统。算法
Kademlia将网络设计为一个具备160层的二叉树,树最末端的每一个叶子即是一个节点,节点在树中的位置由一样是160bit的节点ID决定。
每一个bit的两种可能值(0或1), 决定了节点在树中属于左面仍是右面的子树,160层下来,每一个节点ID便都有了一个肯定的位置。网络
Kademlia使用独特的异或距离算法来计算节点间的距离,异或是一种简单的数学计算,它有不少独特的性质,这些性质在以后会为咱们带来方便:分布式
本身与本身的距离为0: x ^ x = 0 不一样的节点间必有距离: x ^ y > 0 交换律,x到y的距离等于y到x的距离: x ^ y = y ^ x 从a经b绕到c, 要比直接从a到c距离长: a ^b + b ^ c >= a ^ c 下面两个是资料上提到的,彷佛很重要,但我不大理解他们的含义: a + b >= a ^ b (a ^ b) ^ (b ^ c) = a ^ c
在Kademlia中,异或(距离)算法具备单向性(或者说一一对应关系),即给定一个节点和一个距离,一定存在惟一一个相对应节点。包括距离算法在内的,Kademlia中大部分的概念,都既有算术上的意义,又能够在节点树上表现实际意义。
事实上,节点间距离反映的就是节点ID中比特的差别状况,并且越靠前的比特权值越大。或者说是反映节点在树中相隔了多少个分支,须要向上多少个树节点才能找到共同的祖先节点。设计
Kademlia中使用了名为K-桶的概念来储存其余(临近)节点的状态信息,这里的状态信息主要指的就是节点ID, IP, 和端口。
对于160bit的节点ID, 就有160个K-桶,对于每个K-桶i, 它会储存与本身距离在区间 [2^i, 2^(i+1)) 范围内的节点的信息,每一个K-桶中储存有k个其余节点的信息,在BitTorrent的实现中,k的取值为8.code
下表反映了每一个K-桶所储存的信息排序
K-桶 | 储存的距离区间 | 储存的距离范围 | 储存比率 |
0 | [20, 21) | 1 | 100% |
1 | [21, 22) | 2-3 | 100% |
2 | [22, 23) | 4-7 | 100% |
3 | [23, 24) | 8-15 | 100% |
4 | [24, 25) | 16-31 | 75% |
5 | [25, 26) | 32-63 | 57% |
10 | [210, 211) | 1024-2047 | 13% |
i | [2i, 2i+1) | / | 0.75i-3 |
放在节点树上,即每一个节点都更倾向于储存与本身距离近的节点的信息,造成 储存的离本身近的节点多, 储存离本身远的节点少 的局面。
从上表能够看出,在1-15这个范围内的节点,只要发现,就会被100%地储存下来,而离本身距离在1000左右的节点,只会储存13%.递归
对于一个节点而言,K-桶就表明着节点树上那些未知的节点(其实除了本身都是未知的)构成的子树,160个K桶分别是具备1到160层的子树,由小至大。对于节点ID, 160个K-桶分别储存着节点ID前0到159个bit和本身一致的节点。数学
K-桶中的条目(其余临近节点的状态信息)排序的,每当收到一个消息(如查询)时,就要更新一次K桶。
首先计算本身与对方的距离,而后储存到对应的K-桶中,但若是K-桶已满(前面提到每一个K-桶储存有k=8个条目), 则会倾向放弃储存,继续保持旧的节点信息(若是还有效的话). 除了距离外,Kademlia更倾向于与在线时间长,稳定的节点创建联系。
这是由于实践证实,累积在线时间越长的节点越稳定,越倾向于继续保持在线,即节点的失效几率和在线时长成反比。
这样还能够在必定程度上抵御攻击行为。由于当大量恶意的新节点涌入时,你们都会选择继续保持旧的节点信息,而不是接受新的。
除此以外,还须要定时检查K-桶中的节点是否任然在线,及时删去已失效节点。it
Kademlia协议仅定义了四种操做:table
当查找一个节点时,首先计算本身与目标节点的距离d, 而后将 log2d 向下取整,找到对应的K-桶,从这个K-桶中选取a个节点(在BitTorrent的实现中取值为3), 向它们发送查询。
收到查询的节点一样计算距离后从本身的对应K-桶中选取a个节点返回给查询者。查询者不断重复这个过程,知道找到目标节点,或没法再找到更近的结果。
不少资料将这个过程描述成是递归的,但我以为这里认为它是迭代的更为恰当。
由于每一个节点都更倾向于储存距本身近的节点的信息,而整个网络又是一个二叉树,所以每次查询都会至少取得距离减半的结果,对于有N个节点的网络,至多只须要 log2N 次查询。
当进行 FIND VALUE 操做时,查询操做是类型的,每份数据都有一个一样是160bit的键,没分数据都倾向于储存在与键值距离较近的节点上。
当上传者上传一份数据时,上传者首先定位几个较为接近键值的节点,用STORE操做要求他们储存这份数据。
储存有数据的节点,每当发现比本身与键值距离更为接近的节点时,便将数据复制一份到这个节点上。
当一个新节点欲加入网络时,只需找到一个已在网络中的节点,借助它对本身的节点ID进行一次常规查询便可,这样便完成了对本身信息的广播,让距本身较近的节点获知本身的存在。而离开网络没必要执行任何操做,一段时间后,你的信息会自动地从其余节点被删除。
Kademlia的精妙之处在于它选择了异或运算做为计算距离的依据,异或运算不只具备算术的意义,在二叉树式的网络模型中,一样具备实际意义,同时任何状况下都在强调距离的概念,让节点间经过距离来聚合起来。