一致性哈希 (Yīzhìxìng Hāshīng)

一致性哈希算法

如果要将多个数据分散到任意节点上,有一种方法是将数据的ID或哈希值除以保存节点的总数,然后得到保存的节点。然而,这种方法的缺点是如果节点数量发生变化,将导致整个数据的节点移动。
因此,在节点数量增减时,可以使用一种称为一致性哈希的数据布局方法,以确保最低限度的数据移动。
这种方法被用于分布式数据库,如Cassandra和Amazon Dynamo,用于确定数据的存储位置。

スクリーンショット 2019-07-09 午後6.29.21.png

大致的方法

请提醒我,如果有任何不足之处。

对于数据和节点的ID,使用同一个可进行大小比较的哈希函数。

将哈希函数应用于密钥(数据的ID)。

# 今回はハッシュ関数にmd5を使用
import hashlib

hashed_key = hashlib.md5(str(key)).hexdigest()

在节点(容器)的一侧也应用相同的哈希函数

# IDが1~5のノードを用意する
node_ids = range(1, 6)

# (ノードIDのハッシュ値 ,ノードID) のリストを用意
def get_hashed_node_list(node_ids):
    """
    :type node_ids: list of int
    :rtype list 
    """
    hashed_node_list = []
    for node_id in node_ids:
        hashed_node_id = hashlib.md5(str(node_id).encode('utf-8')).hexdigest()
        hashed_node_list.append((hashed_node_id, node_id))
    # ハッシュ値でソートしておく
    return sorted(hashed_node_list, key=lambda n: n[0])

hashed_node_list = get_hashed_node_list(node_ids)

# ノードIDとハッシュ値の対応は以下のようになる
# 1 => c4ca4238a0b923820dcc509a6f75849b
# 2 => c81e728d9d4c2f636f067f89cc14862c
# 3 => eccbc87e4b5ce2fe28308fd9f2a7baf3
# 4 => e4da3b7fbbce2345d7772b0674a318d5
# 5 => e4da3b7fbbce2345d7772b0674a318d5

将节点以环形方式排布

以以下顺序确定分配数据的节点:
1. 与键具有相同哈希值的节点。
2. 在具有大于键的哈希值的节点中,选择哈希值最小的节点。
3. 选择哈希值最小的节点。


def get_node_id(hashed_key, hashed_node_list):
    """
    :type hashed_key: str
    :type hashed_slots: list of (hashed_node_id, node_id)
    :rtype int 
    """
    for hashed_node_id, node_id in hashed_node_list:

        if hashed_key == hashed_node_id:
            # 1. キーと同じハッシュ値のノード
            return node_id

        if hashed_key < hashed_node_id:
            # 2. キーより大きいハッシュ値を持つノードの中で、ハッシュ値が最小のノード
            return node_id

    # 3. どれにもヒットしなければハッシュ値が最小のノード
    return hashed_nodes[0][1]

添加数据

key_list = range(1, 21)
nodes = {i: [] for i in range(1, 6)}

hashed_node_list = get_hashed_node_list(nodes.keys())

for key in key_list:
    hashed_key = hashlib.md5(str(key).encode('utf-8')).hexdigest()
    target_node_id = get_node_id(hashed_key, hashed_node_list)
    nodes[target_node_id].append(key)

假设数据的键为1到20的连续ID,那么每个节点的分配情况如下。


for k, v in nodes.items():
    print('{} {}'.format(k, v))

1 [1, 12, 14]
2 [2, 13, 16]
3 [3]
4 [4, 6, 7, 9, 11, 15, 17, 18, 19, 20]
5 [5, 8, 10]
スクリーンショット 2019-07-20 午後7.40.49.png

如果从这里开始删除5个节点…

1 [1, 12, 14]
2 [2, 13, 16]
3 [3, 5, 8, 10]
4 [4, 6, 7, 9, 11, 15, 17, 18, 19, 20]
スクリーンショット 2019-07-09 午後6.45.47.png

另外,如果添加节点6…

1 [1, 12, 14]
2 [2, 13, 16]
3 [3]
4 [4, 7, 9, 11, 15, 17, 18, 19, 20]
5 [5, 8, 10]
6 [6]
スクリーンショット 2019-07-09 午後6.53.07.png

在整体节点数较少的阶段,一个缺点是每个节点之间出现数据偏差的现象。因此,通过在节点间放置虚拟节点的方法来尽可能均匀地分布数据,被广泛采用。

虚拟节点

我会尽快添加。

请看;参见;借鉴;看一下;引用

学习一种称为”一致性哈希”的方法,并尝试实现分布式缓存系统.

广告
将在 10 秒后关闭
bannerAds