一致性哈希 - 通过代码实际了解一致性哈希原理
概述:python 实现一致性哈希的功能,然后通过使用功能来了解原理
我在其他博客中看了很多关于一致性hash的原理,很详细。没有实际的例子,感觉这个理论的应用无从下手。这里我就从实际的例子分析下一致性hash
先上代码
import md5
class HashRing(object):
def __init__(self, nodes=None, replicas=3):
"""
nodes: 节点数
replicas: 虚拟节点个数
"""
self.replicas = replicas
self.ring = dict()
self._sorted_keys = []
if nodes:
for node in nodes:
self.add_node(node)
def add_node(self, node):
"""添加一个节点到 hash 环中, 包括所有的虚拟节点"""
for i in xrange(0, self.replicas):
key = self.gen_key('%s:%s' % (node, i))
self.ring[key] = node
self._sorted_keys.append(key)
self._sorted_keys.sort()
def remove_node(self, node):
"""从 hash 环上移除一个节点, 包括所有的虚拟节点一并移除"""
for i in xrange(0, self.replicas):
key = self.gen_key('%s:%s' % (node, i))
del self.ring[key]
self._sorted_keys.remove(key)
def get_node(self, string_key):
"""
根据关键字获取所属节点
注意: 此处关键字即为需要计算的字符串
"""
return self.get_node_pos(string_key)[0]
def get_node_pos(self, string_key):
"""计算虚拟节点"""
if not self.ring:
return None, None
key = self.gen_key(string_key)
nodes = self._sorted_keys
for i in xrange(0, len(nodes)):
node = nodes[i]
if key <= node:
return self.ring[node], i
return self.ring[nodes[0]], 0
def get_nodes(self, string_key):
"""Given a string key it returns the nodes as a generator that can hold the key.
The generator is never ending and iterates through the ring
starting at the correct position.
"""
if not self.ring:
yield None, None
node, pos = self.get_node_pos(string_key)
for key in self._sorted_keys[pos:]:
yield self.ring[key]
while True:
for key in self._sorted_keys:
yield self.ring[key]
def gen_key(self, key):
"""Given a string key it returns a long value,
this long value represents a place on the hash ring.
md5 is currently used because it mixes well.
"""
m = md5.new()
m.update(key)
return long(m.hexdigest(), 16)
def print_all(self):
"""打印 hash 环所有节点信息"""
if not self.ring:
return None, None
p = dict()
for k in list(set(self.ring.values())):
p[k] = 0
for i, v in enumerate(self._sorted_keys):
p[self.ring[v]] += 1
# print "ring slot %d is node %s, hash vale is %s" % (i, self.ring[i], v)
print "[{0}] node:{1}#{2} value:{3}".format(i, self.ring[v], p[self.ring[v]], v)
第一步: 创建2个节点的环,每个节点包含3个虚拟节点

上图中前面的 0-5 代表总共有 6 个节点,a#1 表示 a 节点的第一个虚拟节点。图上的value值是按照从小到大的顺序排列,在 hash 环上分布如下图所示

第二步: 计算 key 所属节点,以 ip 举例(字符串类型的都能计算)

上图计算了这三个 ip 所归属的节点,下面具体说明是怎么计算出来的

首先计算 '192.168.184.1' 的 hash 值,然后从环上找到第一个大于该值的节点返回
注意:1. 这里是找到的虚拟节点,然后返回的实际节点
2. 如果没有找到就返回第一个节点
添加一个节点

添加的 c 节点,包含了所有的虚拟节点,总共节点数增加了 3
删除一个节点

这里将 b 节点删除了, 在 hash 环上所有的虚拟节点都被删除了
注意:添加节点或者删除节点后,需要将两个节点间的数据重新计算然后分配

浙公网安备 33010602011771号