Chord算法

转自:http://blog.csdn.net/wangxiaoqin00007/article/details/7374833

虽然网上搜索CHord,一搜一大堆,但大多讲得不太清楚明白。今天发现一篇blog,图文并茂,逻辑清楚且易懂,特意转载收藏。

 

P2P的一个常见问题是如何高效的定位节点,也就是说,一个节点怎样高效的知道在网络中的哪个节点包含它所寻找的数据,如下图:

clip_image002

对此,有三种比较典型的来解决这个问题。

Napster:使用一个中心服务器接收所有的查询,服务器告知去哪下载其所需要的数据。存在的问题是中心服务器单点失效导致整个网络瘫痪。

clip_image004

Gnutella:使用消息洪泛(message flooding)来定位数据。一个消息被发到系统内每一个节点,直到找到其需要的数据为止。当然,使用生存时间(TTL)来限制网络内转发消息的数量。存在的问题是消息数与节点数成线性关系,导致网络负载较重。

clip_image006

SN型:现在大多数采用所谓超级节点(Super Node),SN保存网络中节点的索引信息,这一点和中心服务器类型一样,但是网内有多个SN,其索引信息会在这些SN中进行传播,所以整个系统的崩溃几率就会小很多。尽管如此,网络还是有崩溃的可能。

现在的研究结果中,Chord、Pastry、CAN和Tapestry等常用于构建结构化P2P的分布式哈希表系统(Distributed Hash Table,DHT)。

DHT的主要思想是:首先,每条文件索引被表示成一个(K, V)对,K称为关键字,可以是文件名(或文件的其他描述信息)的哈希值,V是实际存储文件的节点的IP地址(或节点的其他描述信息)。所有的文件索引条目(即所有的(K, V)对)组成一张大的文件索引哈希表,只要输入目标文件的K值,就可以从这张表中查出所有存储该文件的节点地址。然后,再将上面的大文件哈希表分割成很多局部小块,按照特定的规则把这些小块的局部哈希表分布到系统中的所有参与节点上,使得每个节点负责维护其中的一块。这样,节点查询文件时,只要把查询报文路由到相应的节点即可(该节点维护的哈希表分块中含有要查找的(K,V)对)。

这里介绍的Chord算法就是解决网络内节点定位问题的一种P2P协议。它通过多个节点跳转找到我们所查找的资源:

clip_image008

我们先看看它是如何进行的,随后再总结其特点和操作特征,以及一些实现。

1.Chord里面的基本要素

节点ID:NID(node identifier),表示一个物理机器,m位的一个数字(m要足够大以保证不同节点的NID相同的几率小的可以忽略不计),由节点机器的IP地址通过哈希操作得到。

资源ID;KID(key identifiers),原为键ID,其实际表示一个资源(因为Key与一个资源value哈希绑定),故在本文中统称资源ID(这样比较直观),m位的一个数字(m要足够大以保证不同资源的KID相同的几率小的可以忽略不计),由Key通过哈希操作得到。

常哈希函数:较之一般哈希函数,节点的加入和离开对整个系统影响最小,另外还有一些优势在此不赘述。在Chord中使用SHA-1来进行常哈希计算。

Chord环:Chord Ring,NID和KID被分配到一个大小为2^m的环上,用于资源分配(给某一个节点)和节点分布,以及资源定位(注:在这个环上的ID为0--2^m-1)。首先我们说资源分配,资源被分配到NID>=KID的节点上,这个节点成为k的后继节点,是环上从k起顺时针方向的第一个节点,记为successor(k)。而节点分布则顺时针将节点N由大到小放在这个环上。例如下边这幅图:

clip_image010

这是一个m=6的环,其中有10个节点,5个资源,K10的后继节点为N14,也就是说K10被分配给了N14。

2.Chord资源定位(Key Location)

资源定位是Chord协议的核心功能,为了便于理解,我们先介绍一个简单的资源定位方法,然后再介绍这个可伸缩的资源定位方法。

简单方法:

考虑如下场景:节点n寻找KID为id的资源,此时节点n首先问询是否在下一个节点上(find_successor),这要看资源k的KID是否在该节点NID和下一个节点的NID之间,若在则说明资源k被分配给了下一个节点,若不在则在下一个节点上发起同样的查询,问询下下一个点是否有该资源。如此迭代下去,用伪代码定义这个操作:

n.find_successor(id) 
   if (id є (n; successor]) 
       return successor; 
   else 
       // 将查询沿着环进行下去 
     return successor.find_successor(id);

例如下图:

clip_image012

节点N8寻找K54这个资源,N8.find_successor(K54)发现下一个节点N14不合符54є (8; 14],于是N14发起同样的搜索,然后一跳一跳后直到节点N56满足54є (51; 56],于是得知资源K54在N56这个节点上。

在一个有N个节点的环上,这样的查找方法显然在最坏的时候要查找N次才能得到所需资源的位置,查找次数与节点个数成线性关系。显然,这样的效率不给力,所以Chord使用了可伸缩资源定位的方式来提高效率。

可伸缩方法:

在每个节点N上都维护了最多有m项(m为ID的位数)的路由表(称为finger table),用来定位资源。这个表的第i项是该节点的后继节位置,至少包含到2^(i-1)后的位置。还是延续上边的例子:

clip_image014

节点N8的路由表中,左边那一栏包含了N8+1到N8+32(2^5-1)的位置,右边那一栏每个位置对应的实际存在的节点。比如N8+1-N14,表示在N8后的第一个位置上的资源由N14来负责。这样记录有以下优势:

每个节点只包含全网中一小部分节点的信息。

每个节点对于临近节点负责的位置知道的更多,比如N8节点对于N14负责的位置知道3处,而对N21负责的位置只知道1处。

路由表通常不包含直接找到后继节点的信息,往往需要询问其他节点来完成。

当在某个节点上查找资源时,首先判断其后继节点是不是就持有该资源,若没有则直接从该节点的路由表从最远处开始查找,看哪一项离持有资源的节点最近(发现后跳转),若没有则说明本节点自身就有要寻找的资源。如此迭代下去。

例如:节点N8寻找K54这个资源

clip_image016

首先,在N8上查找后继节点为N14,发现K54并不符合54є (8; 14]的要求,那么直接在N8的路由表上查找符合这个要求的表项(由远及近查找),此时N8的路由表为:

clip_image018

我们发现路由表中最远的一项N8+32--N42满足42є (8; 54],则说明N42这个点离持有K54这个资源的节点最近(因为N42在该路由表中离N8这个节点最远),那么此时跳到N42这个节点上继续查找。N42的后继节点为N48,不符合54є (42; 48]的要求,说明N48不持有资源54,此时,开始在N42的路由表上查找:

N42节点的路由表为:

clip_image020

我们由远及近开始查找,发现N42+8--N51满足51є (42; 54],则说明N51这个点离持有K54这个资源的节点最近,那么此时跳到N51这个节点上继续查找。N51节点的后继节点为N56,符合54є (51; 56],此时定位完成,N56持有资源节点K54。

用伪代码表示:

// 查询节点n后继节点。 
n.find_successor(id) 
if (id є (n; successor]) 
return successor; 
else n0 = closest_preceding_node(id); 
return n0.find successor(id); 
// search the local table for the highest 
// predecessor of id 
n.closest_preceding_node(id)  
for i = m downto 1 
if (finger[i] є (n; id)) 
return finger[i]; 
return n;

经证明,最多经过O(log N)次查找就能找到一个资源。

3.Chord的节点加入

Chord通过在每个节点的后台周期性的进行stabilization询问后继节点的前序节点是不是自己来更新后继节点以及路由表中的项。

有三个操作: 
join(n0) :n加入一个Chord环,已知其中有一个节点n0.

Stabilize(): n查询其后继节点的前序节点P来决定P是否应该是n的后续节点,也就是说当p不是n本身时,说明p是新加入的,此时将n的后继节点设置为p。

Notify(n0): n0通知n它的存在,若此时n没有前序节点或,n0比n现有的前序节点更加靠近n,则n将其设置为前序节点。

Fix_fingers(): 修改路由表。

具体的,例如:

这是原先的结构:

clip_image022

现在N26节点要加入系统,首先它指向其后继N32,然后通知N32,N32接到通知后将N26标记为它的前序节点(predecessor)。如下图:

clip_image024

然后N26修改路由表,如下图:

clip_image026

下一次N21运行stabilize()询问其后继节点N32的前序节点是不是还是自己,此时发现N32的前序节点已经是N26:

clip_image028

于是N21就将后继节点修改为N26,并通知N26自己已经将其设置为后继节点,N26接到通知后将N21设置为自己的前序节点。

这个加入操作会带来两方面的影响:

1)正确性方面:当一个节点加入系统,而一个查找发生在stabilization结束前,那么此时系统会有三个状态:

A.所有后继指针和路由表项都正确时:对正确性没有影响。

B.后继指针正确但表项不正确:查找结果正确,但速度稍慢(在目标节点和目标节点的后继处加入非常多个节点时)。如下图:

clip_image030clip_image031

C.后继指针和路由表项都不正确:此时查找失败,Chord上层的软件会发现数据查找失败,在一段时间后会进行重试。

总结一下:节点加入对数据查找没有影响。

2)效率方面:当stabilization完成时,对查找效率的影响不会超过O(log N) 的时间。当stabilization未完成时,在目标节点和目标节点的后继处加入非常多个节点时才会有性能影响。可以证明,只要路由表调整速度快于网络节点数量加倍的速度,性能就不受影响。

4.Chord节点失败的处理

我们可以看出,Chord依赖后继指针的正确性以保证整个网络的正确性。但如图,若N14, N21, N32同时失效,那么N8是不会知道N38是它新的后继节点。为了防止这样的情况,每个节点都包含一个大小为r的后继节点列表,一个后续节点失效了就依次尝试列表中的其他后继节点。可以证明,在失效几率为1/2的网络中,寻找后继的时间为O(log N) 。

5.Chord的特征和应用

特征:去中心化,高可用度,高伸缩性,负载平衡,命名灵活。

应用:全球文件系统、命名服务、数据库请求处理、互联网级别的数据结构、通信服务、事件通知、文件共享。

参考文献:

Chord项目网址:http://pdos.csail.mit.edu/chord/

http://net.chinaunix.net/8/2008/07/28/1231438.shtml

转载于:https://www.cnblogs.com/z-sm/p/5058176.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263476.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

地籍宗地出图(一)

在ArcGIS中,我们经常需要标注;在地籍处理中,需要承包地出图。具体的出没有可参考的标准。通常软件中的做法有: 第一种,以村组为背景,将某户的承包地选择出来,并标黑。这样的结果,领导…

黑马程序员_java基础笔记(15)...银行业务调度系统_编码思路及代码

—————————— ASP.NetAndroidIOS开发、.Net培训、期待与您交流!—————————— 1,面试题目:银行业务调度系统 模拟实现银行业务调度系统逻辑,具体需求如下: 银行内有6个业务窗口,1 — 4号窗口…

一次非常有意思的sql优化经历

原文:一次非常有意思的sql优化经历场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表 create table Course(c_id int PRIMARY KEY,name varchar(10))数据100条 学生表: create table Student(id int PRIMARY KEY,name varchar(10))数据70000条 学生成绩表SC…

python matplotlib绘图大全(散点图、柱状图、饼图、极坐标图、热量图、三维图以及热图)...

//2019.7.14晚matplotlib七种常见图像输出编程大全 七种图形汇总输出如下: import numpy as np #导入数据结构nmupy模块import matplotlib.pyplot as plt #导入matplotlib图像输出模块plt.rcParams["font.sans-serif"]["SimHei"] #输出图像的标…

【活动】畅想云端加油站,赢iPad

2019独角兽企业重金招聘Python工程师标准>>> 中石化联手阿里云升级石油化工业务,已运行2月 中石化的“互联网”战略正在不断深化。4月20日消息,中石化与阿里云共同宣布,双方将展开技术合作,借助阿里巴巴在云计算、大数…

编写 Servlet 2.3 Filter

Servlets Filter 是Servlet 2.3 规范中新增加的,它是截取用户从客户端提交的请求,在还没有到达需要访问的资源时运行的一个类。它操纵来自客户端的请求,在资源还没有初发送到客户端前截取响应,并处理这些还没有发送到客户端的响应…

我记录网站综合系统 -- 技术原理解析[0:简介(代序) 1.7Beta源代码下载开始]...

看到了路过秋天的博客系统受到了大家的好评,我也来介绍一个好的开源的CMS系统。我记录网站综合系统 是 掷鸡蛋者 的作品,这个家伙将大量的时间和精力放在这个项目上了,可以算一个创业项目。对于这样的同志,我只有敬佩他和全力支持…

PowerShell在Exchange2010下快速创建动态通讯组

Exchange中遇到一个小需求,有很多部门要申请动态通信组,问题是二级部门三级部门四级部门非常非常多。……Get-ADObject -LDAPFilter "(&(&(ou>"")))" -SearchBase OUxx,OUxxx,DCxxx,DCxxx,DCcom -Properties CanonicalNa…

LeetCode—262. 行程和用户(困难)

262. 行程和用户(困难) 题目描述: 取消率 的计算方式如下:(被司机或乘客取消的非禁止用户生成的订单数量) / (非禁止用户生成的订单总数)。 写一段 SQL 语句查出 “2013-10-01” 至 “2013-10-03” 期间非禁止用户(乘客和司机都必须未被禁止…

第5章 JVM调优

2019独角兽企业重金招聘Python工程师标准>>> ##5.1 Java虚拟机内存模型## Java虚拟机内存模型是Java程序运行的基础。JVM将其内存数据分为程序计数器,虚拟机栈,本地方法栈,Java堆和方法区等部分。 程序计数器:用于存放…

C语言讲义——字符串

字符数组 C语言字符串就是字符数组。 单写字符&#xff0c;用单引号。如&#xff1a;’A’。字符串用双引号。如&#xff1a;”A”、”ABC”。#include <stdio.h> main() {char c1 a;printf("%c\n", c1-1);printf("%c\n", c1);printf("%c\n&qu…

c基础--II

c基础&#xff0d;&#xff0d;II 数据输出putchar()函数#include "stdio.h"main(){ char a,b,c; aa; bb; cc; //putchar()函数 putchar(a); putchar(b); putchar(c);}printf()函数printf(格式控制&#xff0c;输出列表)%d 输出 十进制整数%o 输出 八进…

Chuck Cobb谈敏捷组织中PMO的角色

对于设立了PMO&#xff08;项目管理办公室&#xff09;的企业&#xff0c;实施整个企业向敏捷风格的转换可能需要多个部门同步改变工作方式。在敏捷的团队中&#xff0c;PMO的传统角色需要做出改变。Charles G. “Chuck” Cobb,专家级敏捷项目经理、顾问、图书作者,最近分享了对…

极客

2019独角兽企业重金招聘Python工程师标准>>> 极客是美国俚语“geek”的音译。随着互联网文化的兴起&#xff0c;这个词含有智力超群和努力的语意&#xff0c;又被用于形容对计算机和网络技术有狂热兴趣并投入大量时间钻研的人。现代的Geek含义虽然与过去有所不同&am…

大数据——SparkStreaming学习笔记

Spark 一、SparkStreaming ​ Spark Streaming 用于流式数据的处理&#xff08;准实时&#xff0c;微序列&#xff09;。Spark Streaming 支持的数据输入源很多&#xff0c;例如&#xff1a;Kafka、 Flume、Twitter、ZeroMQ 和简单的 TCP 套接字等等。数据输入后可以用 Spark…

[推荐]ORACLE SQL:经典查询练手第三篇(不懂装懂,永世饭桶!)

[推荐]ORACLE SQL&#xff1a;经典查询练手第三篇(不懂装懂&#xff0c;永世饭桶&#xff01;) [推荐]ORACLE SQL&#xff1a; 经典查询练手第三篇(不懂装懂&#xff0c;永世饭桶&#xff01;) ——通过知识共享树立个人品牌。 本文与大家共同讨论与分享ORACLE SQL的一些常用经…

DotNET多线程使用初探

最近几周一直在做DotNET WinForm开发&#xff0c;陆陆续续有些收获&#xff0c;希望能够有空好好整理整理。记下来以免以后又忘了。:-) 一、最简单的线程使用方法 新建一个C# Windows应用程序项目&#xff0c;在最前面的引用代码那增加一行using System.Threading;在界面上扔个…

大数据——Spark学习笔记(配置)

Spark运行环境 spark ui web http://hadoop102:8080 历史服务器 http://hadoop102:18080 一. 本地模式(Local)——单机运行 本地模式&#xff1a;运行 bin/spark-shell提交应用&#xff1a;运行 bin/spark-submit --class org.apache.spark.examples.SparkPi …

大数据——Hive学习笔记

具体代码可以参考&#xff1a; https://github.com/Ostrich5yw/java4BigData