一、背景
1.命名系统:
分布式系统的命名系统主要是为了解决Name 与 Address 的对应问题,即如何使用 Name 找到 Address
几个概念:
Name: 表示名称的字符串
entity: 实体 —— 资源,如硬盘,主机等
Address: 将 Name 赋值给 Access Point , 这个 Access Point 就成为了 Address,即 Address 就是访问点的名字,通过 Address 我们可以找到某种 entity 即资源
2. 解决 Name 到 Address 间映射的其他方法
(1)Flat Name —— 平面命名法
平面命名法通过广播和多波的形式,建立 MapTable ,通过留转发指针的方式解决节点移动问题,但这种方法耗费通信资源,并且大量的转发指针不利于管理
(2)Home-Based Approach —— 基于主站的查找法
通过建立一个主站,保持所有的 Name 和 Address 的映射关系,节点先访问主站,主站将节点要查询的地址返回,节点再根据返回的地址进行下一步操作。但是这种方式,主站存放了大量信息,不符合分布式系统的概念,且不具有地区友好性
图. 跨地区较远时,来回发送,浪费资源
因此,引入分布式哈希表,即 Chord 这一数据结构,下面重点介绍 Chord 用法
二、Chord —— 分布式哈希表
1. 术语:
Chord 数据结构使用 m 位的标识空间(2的m次方个数字 )指定 node 和 key(m = 128 或 160)
- ID: 0 ~ 2 的m次方 - 1 , 表示 Address 和 Name 的所有可用名字
- NID(NodeID) 0 ~ 2 的m次方 - 1,用于表示Address,如服务器地址
- KID(KeyID) 0 ~ 2 的m次方 - 1,用于表示entity,如文件名
2. 实现方式:
Chord 通过抽象一个环形数据结构的方式,环上的点表示 Address 即 NID,NID通过后继指针连接下一个 NID,并通过用指针将 KID连接到环上的 NID 的方式实现 NID 与 KID 的映射,该算法可以达到查找时 logn 的时间复杂度
(1)示例图:
示例图解释:
m = 6 说明一共有 (0 ~ 63)个ID 可以用来命名,即 NID (0 ~ 63 之间),且 KID(0~63 之间) 。
- NID的放置: 图中圆上共有 N1,N8,N14 … 等 NID(即 Address,也可理解为服务器),(N1 - N8 间无节点,N1指向 N8,若加入 N6,则将其加入两者之间,并修改指针即可)。
- KID的放置: 以 N14 为例,若要插入 K10,则去找 10 的最近后继节点,本图中,节点 10 的最后一个后继节点为 N14,因此将 K10 指向 N14
(2)如何找到某 KID 所在的 NID
- Basic Query:从某一 NID 开始,依此向其后继节点查找,这样的搜索方式时间复杂度为O(n)显然是非常大的,这不是我们想要的。
- Finger Table (建立指表):
显然,之所以查找慢,是因为每个NID都只知道找其紧紧相邻的后继节点,因此我们可以通过为每个 NID 建立包含其部分后继 NID 的指表的方式,减低时间复杂度
指表建立方式:
我们知道了建立指表可以减少时间复杂度,就来到了下个问题指表中应该保存那些后继节点,其计算公式为
找到上述计算公式结果的 下一个后继 NID,保持在指表中,作为 NID = n 节点的指表
示例: N8 的指表中所含后继节点的计算
通过指表进行查找:
以上图为例:我们需要 N1 找到 K20,我们就可以现在 N1 的指表中找到 K20 的上一个节点,可以判断为 N8,因此之间转到 N8。然后在 N8 找 K20 的上个节点,可以观察到就是 K20 本身,因此之间转到 K20 即可,查找结束。通过上述过程,我们也可以得出通过建立指表的方式可以极大的降低查找过程的时间复杂度
指表的其他优点:
- 完全分布式,无中央节点
- 新增节点容易,变化小