背景:
当客户端调用redis缓存集群(比如3台)存取数据时,
如果客户端采用普通的hash求余(id%3)的算法,来计算该数据应该由哪台redis服务器存取,
当算法是:id%机器数,redis服务器和id的对应关系有:
id%3时===>redis1:0/3/6/9,redis2:1/4/7,redis3:2/5/8,
当redis集群中一台服务器 redis3 down掉后,hash值从id%3变成了id%2,变成:
id%2时===>redis1:0/2/4/6/8,redis2:1/3/5/7
可见很多数据需要迁移:2/3/4/5/8/9都需要迁移
设想一下:
怎么在服务器down掉后,尽量少地迁移数据呢?
如果down掉的redis服务器不会影响其他redis服务器上数据存储,是不是需要迁移的数据就会变少呢!
===>当redis3down掉了,只会影响redis3上的数据,那需要迁移的数据就只有redis3上的2/5/8
为了达到上面的目的,一致性hash算法就该出场了。
实现:
一致性hash算法为了达到这个目的,引入了一个虚拟节点的概念。
之前咱们是通过id求余,计算出需要将id放到哪台redis服务器的,即对应关系是:
id===>服务器
比如:id%redis服务器数量=对象存储的redis服务器序号
id=4,redis有3台,则4%3=1,所以对象放到第一台服务器redis1。
在添加虚拟节点作为中间层之后,现在咱们不再把id和服务器对应起来,而是通过中间层联系起来
id===>虚拟节点序号===>服务器
比如:还是id为0->9的10个对象;redis服务器还是3台;假定中间层序号是z0->z9
1)将id映射到环上,假如环上节点号的算法是:id%虚拟节点数,则分别一个id对应一个节点:
0=>z0,1=>z1,2=>z2 ...z9=>z9
2)将redis服务器映射到环上,假如环上节点号的算法是:redis服务器序号*3,则有:
redis1=>z3,redis2=>z6,redis3=>z9
3)环上的节点由哪台redis服务器管理呢?我们可以定义规则:从该节点开始,在环上顺时针查找,
找到的第一个服务器管理这个节点。
所以redis服务器需要管理的环上的区域有:
redis1:z0/z1/z2/z3 redis2:z4/z5/z6 redis3:z7/z8/z9
对应的id也是:
redis1:0/1/2/3 redis2:4/5/6 redis3:7/8/9
则服务器redis3 down掉后,
1)中的对象id在环上的位置不变,还是0=>z0,1=>z1,2=>z2 ...z9=>z9
2)中redis1 和redis2在环上的位置也不会变,还是redis1=>z3,redis2=>z6
所以只有redis3区域的id(7/8/9)需要改变。
这时id(7/8/9)在环上顺时针查找的节点是redis1,所以redis3上的数据会放到redis1上。
大功告成!这里的说法有些地方不太准确,主要是为了说明过程,想了解具体过程的可以看看其他文章的准确描述