分散式杂凑表

分散式杂凑表（distributed hash table，缩写DHT）是一类分散式计算系统，用于将关键值（key）集合分散到系统中的各个节点，并有效地把查询讯息转送至持有相应关键值的节点（peer）。此处的节点类似杂凑表中的储存位置。分散式杂凑表通常面向节点数量极大、且节点经常加入或离开（如网络断线）的系统设计。在结构化覆盖网络（overlay network）中，参与节点只需与系统中的一小部分节点沟通，也常使用分散式杂凑表。分散式杂凑表可用于建立更复杂的服务，例如分散式档案系统、点对点技术档案分享系统、合作的网页快取、多播、任播、域名系统以及即时通讯等。

## 发展背景

研究分散式杂凑表的主要动机是为了开发点对点系统，像是Napster、Gnutella及Freenet。这些系统得益于使用分散在互联网上的各项资源以提供实用的应用，特别在带宽及硬盘储存空间上，他们所提供的档案分享功能因此得到最大的好处。

这些系统使用不同的方法来解决如何找到拥有某资料的节点的问题。Napster使用中央的索引服务器：每个节点加入网络的同时，会将他们所拥有的档案列表传送给服务器，这使得服务器可以进行搜寻并将结果回传给进行查询的节点。但中央索引服务器让整个系统易受攻击，且可能造成法律问题。于是，Gnutella和相似的网络改用大量查询模式，每次搜寻都会把查询讯息广播给网络上的所有节点。虽然这个方式能够防止单点故障，但比起Napster来说却极没效率。

最后，Freenet使用了完全分散式的系统，但它建置了一套使用经验法则的基于关键值的转送方法。在这个方法中，每个档案与一个关键值相结合，而拥有相似关键值的档案会倾向被相似的节点构成的集合所保管。于是查询讯息就可以根据它所提供的关键值被转送到该集合，而不需要经过所有的节点。然而，Freenet并不保证存在网络上的资料在查询时一定会被找到。

分散式杂凑表为了达到Gnutella与Freenet的分散性（decentralization）以及Napster的效率与正确结果，使用了较为结构化的基于关键值的转送方法。不过分散式杂凑表也有个Freenet有的缺点，就是只能作精确搜寻，而不能只提供部分的关键字；但这个功能可以在分散式杂凑表的上层实做。

最初的四项分散式杂凑表技术——内容可定址网络、Chord project、Pastry (分散式杂凑表)以及Tapestry (分散式杂凑表)皆同时于2001年发表。从那时开始，相关的研究便一直十分活跃。在学术领域以外，分散式杂凑表技术已经被应用在BitTorrent及CoralCDN等。

## 性质

分散式杂凑表本质上强调以下特性：

- 离散性：构成系统的节点并没有任何中央式的协调机制。
- 伸缩性：即使有成千上万个节点，系统仍然应该十分有效率。
- 容错性：即使节点不断地加入、离开或是停止工作，系统仍然必须达到一定的可靠度。

要达到以上的目标，有一个关键的技术：任一个节点只需要与系统中的部分节点沟通。一般来说，若系统有$n$个节点，那么只有$\Theta(\log n)$个节点是必须的（见后述）。因此，当成员改变的时候，只有一部分的工作（例如资料或关键值的传送，杂凑表的改变等）必须要完成。

有些分散式杂凑表的设计寻求能对抗网络中恶意的节点的安全性，但仍然保留参加节点的匿名性。在其他的点对点系统（特别是档案分享）中较为少见。参见匿名点对点技术。

最后，分散式杂凑表必须处理传统分散式系统可能遇到的问题，例如负载平衡、资料完整性，以及效能问题（特别是确认转送讯息、资料储存及读取等动作能快速完成）。

## 结构

分散式杂凑表的结构可以分成几个主要的元件。其基础是一个抽象的关键值空间（keyspace），例如说所有160位元长的字元串集合。关键值空间分割（keyspace partitioning）将关键值空间分割成数个，并指定到在此系统的节点中。而延展网络则连接这些节点，并让他们能够借由在关键值空间内的任一值找到拥有该值的节点。

当这些元件都准备好后，一般使用分散式杂凑表来储存与读取的方式如下所述。假设关键值空间是一个160位元长的字元串集合。为了在分散式杂凑表中储存一个档案，名称为$filename$且内容为$data$，我们计算出$filename$的SHA1杂凑值——一个160位元的关键值$k$——并将讯息$put(k, data)$送给分散式杂凑表中的任意参与节点。此讯息在延展网络中被转送，直到抵达在关键值空间分割中被指定负责储存关键值$k$的节点。而$(k, data)$即储存在该节点。其他的节点只需要重新计算$filename$的杂凑值$k$，然后送出讯息 $get(k)$给分散式杂凑表中的任意参与节点，以此来找与$k$相关的资料。此讯息也会在延展网络中被转送到负责储存$k$的节点。而此节点则会负责传回储存的资料$data$。

以下分别描述关键值空间分割及延展网络的基本概念。这些概念在大多数的分散式杂凑表实作中是相同的，但设计的细节部分则大多不同。

### 关键值空间分割

大多数的分散式杂凑表使用某些稳定杂凑（consistent hashing）方法来将关键值对应到节点。此方法使用了一个函数$\delta(k_1, k_2)$来定义一个抽象的概念：从关键值$k_1$到$k_2$的距离。每个节点被指定了一个关键值，称为ID。ID为$i$的节点拥有根据函数$\delta$计算，最接近$i$的所有关键值。

例：Chord分散式杂凑表实作将关键值视为一个圆上的点，而$\delta(k_1, k_2)$则是沿着圆顺时钟地从$k_1$走到$k_2$的距离。结果，圆形的关键值空间就被切成连续的圆弧段，而每段的端点都是节点的ID。如果$i_1$与$i_2$是邻近的ID，则ID为$i_2$的节点拥有落在$i_1$及$i_2$之间的所有关键值。

稳定杂凑拥有一个基本的性质：增加或移除节点只改变邻近ID的节点所拥有的关键值集合，而其他节点的则不会被改变。对比于传统的杂凑表，若增加或移除一个位置，则整个关键值空间就必须重新对应。由于拥有资料的改变通常会导致资料从分散式杂凑表中的一个节点被搬到另一个节点，而这是非常浪费带宽的，因此若要有效率地支援大量密集的节点增加或离开的动作，这种重新配置的行为必须尽量减少。

将相近的关键值分配给了距离相近的节点，可以实现更短的查询延迟，从而提高DHT的查询效率。相关工作包括Self-Chord和LDHT

### 延展网络

每个节点保有一些到其他节点（它的邻居）的连结。将这些连结总合起来就形成延展网络。而这些连结是使用一个结构性的方式来挑选的，称为网络拓朴。

所有的分散式杂凑表实作拓朴有某些基本的性质：对于任一关键值$k$，某个节点要不就拥有$k$，要不就拥有一个连结能连结到距离较接近$k$的节点。因此使用以下的贪心算法即可容易地将讯息转送到拥有关键值$k$的节点：在每次执行时，将讯息转送到ID较接近$k$的邻近节点。若没有这样的节点，那我们一定抵达了最接近$k$的节点，也就是拥有$k$的节点。这样的转送方法有时被称为“基于关键值的转送方法”。

除了基本的转送正确性之外，拓朴中另有两个关键的限制：其一为保证任何的转送路径长度必须尽量短，因而请求能快速地被完成；其二为任一节点的邻近节点数目（又称最大节点度（Degree (graph theory)））必须尽量少，因此维护的花费不会过多。当然，转送长度越短，则最大节点度越大。以下列出常见的最大节点度及转送长度（$n$为分散式杂凑表中的节点数）

- 最大节点度$O(1)$，转送长度$O(\log n)$
- 最大节点度$O(\log n)$，转送长度$O(\log n / \log \log n)$
- 最大节点度$O(\log n)$，转送长度$O(\log n)$
- 最大节点度$O(n^{1/2})$，转送长度$O(1)$

第三个选择最为常见。虽然他在最大节点度与转送长度的取舍中并不是最佳的选择，但这样的拓朴允许较为有弹性地选择邻近节点。许多分散式杂凑表实作利用这种弹性来选择延迟较低的邻近节点。

最大的转送长度与直径有关：最远的两节点之间的最短跳数（Hop Distance）。无疑地，网络的最大转送长度至少要与它的直径一样长，因而拓朴也被最大节点度与直径的取舍限制住，而这在图论中是基本的性质。因为贪婪算法（Greedy Method）可能找不到最短路径，因此转送长度可能比直径长。

## 范例

### 分散式杂凑表实作与协定

- Bamboo
- Bunshin
- 内容可定址网络（Content Addressable Network）
- DKS系统
- Kademlia
- Leopard

### 分散式杂凑表的应用

- BitTorrent：档案分享应用。BitTorrent可以选用DHT作为分散式Tracker。
- 档案分享应用。
- The Circle：档案分享应用与聊天。
- CSpace：安全的沟通系统。
- 网页快取。
- Dijjer
- eMule：档案分享应用。
- I2P：匿名网络。
- 开放源代码的点对点平台。
- NEOnet：档案分享应用。
- Overnet：档案分享应用。

## 外部链接

- Distributed Hash Tables, Part 1 由Brandon Wiley所著。
- Sloppy Hashing and Self-Organizing Clusters由CoralCDN专案提供的著作。
- Tangosol Coherence 介绍一个类似DHT的架构，但所有节点都知道网络中其他参与者的资讯。

## 参见

- memcached：一个高效能、分散式的物件快取系统。