Kademlia算法分析
定义
Kademlia算法是一种分布式哈希存储及路由的算法,每个节点存放部分资源
- 如何分配存储内容到各个节点
- 如何找到存储文件的节点/地址/路径
算法
节点属性
- 节点ID,Node ID
- 节点IP地址与端口号
节点维护信息
- 需要存储的资源,资源以<key, value>对的形式存储,可以理解为文件名的哈希值和文件内容
- 一个路由表,称为“k-bucket”,按Node ID分层,记录有限个数的其他节点的ID和IP地址及端口
关于为什么不是每个节点都维护全量路由信息:
- 分布式系统中节点的进入和退出是相当频繁的,每次有变动时都全网广播通讯录更新,通讯量会很大
- 一旦任意节点被黑客攻破,则坏人马上就拥有了所有节点的信息,这并不安全。
文件的存储及查找
-
资源分配
假设文件名的hash值是 00010000,那么该文件就会被要求存在ID为00010000的同学手上。(这要求hash算法的值域与node ID的值域一致)
万一00010000节点没有上线或彻底退出网络,那算法要求该资源不能只存在一个节点上,而是被要求同时存储在节点ID最接近00010000的k个节点上,即00010001、00010010、00010011…等节点上都会有该文件。
-
资源查找
当你知道目标节点Z与你之间的距离,你可以在你的k-bucket上先找到一个你认为与节点Z最相近的节点B,请节点B再进一步去查找节点Z的IP地址。
这里距离的定义使用了异或距离:
- 01010000与01010010距离(即是2个ID的异或值)为00000010(换算为十进制即为2);
- 01000000与00000001距离为01000001(换算为十进制即为$2^6+1$,即65);
以0000110为基础节点,如果一个节点的ID,前面所有位数都与它相同,只有最后1位不同,这样的节点只有1个——0000111,与基础节点的异或值为0000001,即距离为1;对于0000110而言,这样的节点归为“k-bucket 1”;
如果一个节点的ID,前面所有位数相同,从倒数第2位开始不同,这样的节点只有2个:0000101、0000100,与基础节点的异或值为0000011和0000010,即距离范围为3和2;对于0000110而言,这样的节点归为“k-bucket 2”;
如果一个节点的ID,前面所有位数相同,从倒数第2位开始不同,这样的节点只有2个:0000101、0000100,与基础节点的异或值为0000011和0000010,即距离范围为3和2;对于0000110而言,这样的节点归为“k-bucket 2”;
……
如果一个节点的ID,前面所有位数相同,从倒数第n位开始不同,这样的节点只有$2^{i-1}$个,与基础节点的距离范围为$\left[ 2^{i-1},2^i \right)$;对于0000110而言,这样的节点归为“k-bucket i”;
如果一个节点的ID,前面所有位数相同,从倒数第n位开始不同,这样的节点只有$2^{i-1}$个,与基础节点的距离范围为$\left[ 2^{i-1},2^i \right)$;对于0000110而言,这样的节点归为“k-bucket i”;
每个节点在它自己的每个k-bucket中只记录k个节点的IP信息,(k个节点的地址与端口,这里的k是一个可调节的常量参数)
A节点(ID 00000110)想找《分布式算法》,A首先需要计算书名的哈希值,hash(《分布式算法》) = 00010000。那么A就需要找到00010000号节点(命名为Z)或Z邻近的节点。
Z的节点00010000与自己的异或距离为 00010110,距离范围在[24, 25),所以这个Z可能在k-bucket 5中(或者说,Z与A的ID从第5位开始不同,所以Z可能在k-bucket 5中)。
然后A看看自己的k-bucket 5有没有Z:
- 如果有,那就直接联系Z要书;
- 如果没有,在k-bucket 5里随便找一个B(注意任意B,它的ID第5位肯定与Z相同,即它与Z的距离会小于24,相当于比Z、A之间的距离缩短了一半以上),请求B在它自己的通讯录里按同样的查找方式找一下Z:
-- 如果B知道Z,那就把Z同学的IP 告诉A;
-- 如果B也不知道Z,那B按同样的搜索方法,可以在自己的通讯录里找到一个离Z更近的C(Z、C之间距离小于23),把C推荐给A;A请求C进行下一步查找。
Kademlia的这种查询机制,最多只需要查询$\log _2n$次,即可找到获得目标节点的联系方式。
算法参数
- keyspace
-- 即ID有多少位
-- 决定每个节点的通讯录有几层 - k
-- 每个一层k-bucket里装k个node的信息,即<node ID, IP Adress, port>
-- 每次查找node时,返回k个node的信息
-- 对于某个特定的data,离其key最近的k个节点被会要求存储这个data - α
-- 每次向其他node请求查找某个node时,会向α个node发出请求
节点的指令
Kademlia算法中,每个节点只有4个指令
- PING
-- 测试一个节点是否在线 - STORE
-- 要求一个节点存储一份数据 - FIND_NODE
-- 根据节点ID查找一个节点 - FIND_VALUE
-- 根据KEY查找一个数据,实则上跟FIND_NODE非常类似
k-bucket的维护及更新机制
- 每个bucket里的节点都按最后一次接触的时间倒序排列
- 每次执行四个指令中的任意一个都会触发更新
- 当一个节点与自己接触时,检查它是否在K-bucket中
-- 如果在,那么将它挪到k-bucket列表的最底(最新)
-- 如果不在,PING一下列表最上面(最旧)的一个节点
a) 如果PING通了,将旧节点挪到列表最底,并丢弃新节点
b) 如果PING不通,删除旧节点,并将新节点加入列表
该机制保证了任意节点加入和离开都不影响整体网络。
参考文献