如何在许多数据中快速的找到想要的数据?一个一个的比对肯定非常消耗时间。
Hash函数是一种单向函数,它可以将任意长度的输入变成固定长度的输出,并且,对于一个输出无法找到两个不同的输入。
将资源和url作为hash函数的输入,得到定长的二进制串,并将其存放到一个全局hash表中。
DHT
将之前的全局hash表分散存储到网络上的每个节点上。
例如:
将内容和索引抽象为<K, V>对,其中
K是内容的关键字的摘要,譬如电影:夜宴,K=Hash(“夜宴”);
V是存储该资源的地址,譬如:www.movie.com/yanye.rmvb
所有的资源都以这种形式存储在一张大表上,构成了一张全局Hash表。
然后,在网络上的每个节点随机的生成一个ID,将表里面的<K, V>对按照某种规定的原则(一般是K和ID的关系)存储到各个节点上去,所以,所有的节点就在应用层之上形成了一个重叠网络。
当我们要寻找一个资源时,就可以根据K和ID之间的关联找到存储该<K, V >对的节点,从而找到相应的V,即可以找到资源的下载地址。
下面介绍两种DHT的算法,一种是Chord,另一种是Pastry。
Chord
Chord选择SHA-1作为哈希函数,SHA-1会产生一个2160的空间,每项为一个16字节(160bit)的大整数。我们可以认为这些整数首尾相连形成一个环,称之为Chord环。整数在Chord环上按大小顺时针排列(即Chord环是个有向环),Node(机器的IP地址和Port)与Key(资源标识)都被哈希到Chord环上,这样我们就假定了整个P2P网络的状态为一个虚拟的环,因此我们说Chord是结构化的P2P网络。
如上图所示,每个节点都有自己的ID,该ID是利用SHA-1函数对每个节点的IP进行Hash而得到的,每个节点都维护了一张FingerTable,上面存储的是指向其他节点的指针,每个指针对应一个Hash段。
譬如:从入口节点(本机节点)要寻找一个资源X,先对X求Hash值:K= Hash(X);
在入口节点的FingerTable上寻找,如果刚好有一个等于K,那么对应的<K, V>对就存储在该节点上,比如N8是入口,K=24,刚好N8+16等于24,所以转到N32节点;
若是没有ID为K的节点,则在小于K并离它最进的节点上找,并重复此过程,比如K=53,N8+32<53,所以转到N42,再转到N51,最终找到N51+2,转到N56如下图:
Pastry
Pastry也是将节点按照ID构成一个环,但是是一个无向环,每个节点维护三个表:叶子节点表;路由表;邻居节点表。(如下图)
叶子节点表存储的是该节点在环上的左右几个节点(从ID可以明显看出);
邻居节点表存储的是在物理位置上与该节点相邻的节点;
路由表分层,每列从上到下分别代表与当前节点ID前缀匹配对应位数的节点,其行数就是Pastry采用的进制数。
Pastry的路由算法如下:
//shl(A,D)表示A和D的最长前缀匹配长度
if(L-[|L|/2]<D<L[|L|/2]){//D在叶子节点内
forward to Li,|D-Li|is minimal;
}else{
//使用路由表
l=shl(A ,D);
if(R表的第l行第Di列不为空){
forward it;
}
else{
//路由表项为空
在三个表中找到T,shl(T,D)>l,|T-D|<|A-D|
}
}