Kademlia协议(以下简称Kad),是一种分布式哈希表(DHT,Distributed Hash Table)技术,不过和其他DHT实现技术比较,如Chord、CAN、Pastry等,Kad通过独特的以异或算法(XOR)为距离度量基础,建立了一种全新的DHT拓扑结构,相比于其他算法,大大提高了路由查询速度。
在Kademlia网络中,所有信息均以的哈希表条目形式加 以存储,这些条目被分散地存储在各个节点上,从而以全网方式构成一张巨大的分布式哈希表。我们可以形象地把这张哈希大表看成是一本字典:只要知道了信息索 引的key,我们便可以通过Kademlia协议来查询其所对应的value信息,而不管这个value信息究竟是存储在哪一个节点之上。在eMule、 BitTorrent等P2P文件交换系统中,Kademlia主要充当了文件信息检索协议这一关键角色,但Kad网络的应用并不仅限于文件交换。
节点
每个用户都有一个ID号, ID长度根据不同网络而定,例如以太坊中是512bit,eMule是128bit。在系统设计上的好处是——对分布式系统所依赖的物理网络的解耦。 ID是在你第一次使用Kad时随机生成的. 出现两个相同ID的概率实在太小了, 这几乎不可能发生. 我们可以认为, 在Kad网络里, 没有两个用户具有相同的ID号。
节点ID不仅可以用来做身份标识,还可以用来进行值定位(值通常是文件的散列或者关键词),节点ID与文件散列直接对应,它所表示的那个节点存储着哪儿能够获取文件和资源的相关信息
很多 DHT 的设计会让“node ID”采用跟“data key”同构的哈希值。这么搞的好处是:1、当散列值空间足够大的时候,随机碰撞忽略不计,因此也就确保了 node ID 的唯一性。2、可以简化系统设计——比如简化路由算法,采用这种风格来设计路由机制,好处是:key 本身已经提供了足够多的路由信息。
距离
在Kad网络中,两个节点之间距离并不是依靠物理距离、路由器跳数来衡量的,事实上,Kad网络将任意两个节点之间的距离d定义为其二者ID值的逐比特二进制和数,即异或。假定两个节点的ID分别为a与b,则有:d=a XOR b。在Kad中,每一个节点都可以根据这一距离概念来判断其他节点距离自己的“远近”,当d值大时,节点间距离较远,而当d值小时,则两个节点相距很近。 这里的“远近”和“距离”都只是一种逻辑上的度量描述而已;
举个例子:
01010000与01010010距离(即是2个ID的异或值)为00000010(换算为十进制即为2);
01000000与00000001距离为01000001(换算为十进制即为26+1,即65);如此类推。
异或计算距离的特点,1、节点和它本身之间的异或距离是0。2、异或距离是对称的:即从A到B的异或距离与从B到A的异或距离是等同的。3、异或距离符合三角形不等式:给定三个顶点A B C,假如AC之间的异或距离最大,那么AC之间的异或距离必小于或等于AB异或距离和BC异或距离之和.4、对于给定的一个距离,距离A只存在有唯一的一个节点B,也即单向性,在查找路径上也是单向的,这个和地理距离不同。
由于以上的这些属性,在实际的节点距离的度量过程中计算量将大大降低。对于越低bit位,XOR可能得到的结果越小,对于越高位的bit位,XOR可能得到的值就越大,并且是呈现2的指数方式增长的,所以,从数学上来说,一个DHT网络中的所有节点,通过这种方式(XOR距离)进行寻址,每次前进一个bit,最大只需要log2N次即可到达目标节点(log2逼近的思路,即bit 2可以表示世界上任何数字)。
路由表
Kad的路由表是通过一些称之为K桶的表格构造起来的。Kad路由表由多个列表组成,每个列表对应节点ID的一位,一个列表中包含多个条目。列表条目中的这些数据通常是由其他节点的IP地址,端口和节点ID组成。
每个列表对应于与节点相距"特定范围距离"的一些节点,节点的第n个列表中所找到的节点的第n位与该节点的第n位肯定不同,而前n-1位相同。这就意味着很容易使用网络中远离该节点的一半节点来填充第一个列表(第一位不同的节点最多有一半),而用网络中四分之一的节点来填充第二个列表(比第一个列表中的那些节点离该节点更近一位),依次类推。如果ID有128个二进制位,则网络中的每个节点按照不同的异或距离把其他所有的节点分成了128类,ID的每一位对应于其中的一类。
K桶的更新机制非常高效的实现了一种把最近看到的节点更新的策略,除非在线节点一直未从K桶中移出过。也就是说在线时间长的节点具有较高的可能性继续保留在K桶列表中。采用这种机制是基于对Gnutella网络上大量用户行为习惯的研究结果,既节点的失效概率和在线时长成反比关系,用户在线时间越长,他在下一时段继续在线的可能性就越高。
所以,通过把在线时间长的节点留在K桶里,Kad就明显增加K桶中的节点在下一时间段仍然在线的概率,这对应Kad网络的稳定性和减少网络维护成本(不需要频繁构建节点的路由表)带来很大好处。这种机制的另一个好处是能在一定程度上防御DOS攻击,因为只有当老节点失效后,Kad才会更新K桶的信息,这就避免了通过新节点的加入来泛洪路由信息。
为了防止K桶老化,所有在一定时间之内无更新操作的K桶,都会分别从自己的K桶中随机选择一些节点执行RPC_PING操作。上述这些K桶机制使Kad缓和了流量瓶颈(所有节点不会同时进行大量的更新操作),同时也能对节点的失效进行迅速响应。