背景
09
年初,我们做了一个
memcached
的智能客户端库,业务只要将这个库链上,就能跟
memcached
服务器通信。并且实现了一致性哈希的分布式算法,后端
memcached
服务器可以无限制扩展,而且客户端能对
memcached
做自动故障转移以及恢复。
我们知道,在没有对数据做冗余存储的情况下,无论是一致性哈希还是求余数分布式算法,在新增或删除
memcached
节点时,命中率都会不同程度的降低。本文旨在解决当新增
memcached
节点时,如何保证命中率不变。
基本原理
当
新增一个
memcached
节点时,将该新节点的下一个节点的且属于该新节点的数据迁移过来。
上面的这个基本原理读起来可能会比较拗口,容我下面详细说明。
原理描述
如图
1
所示,假设当前哈希环上有
n
个
memcached
节点,记为
M
1
~M
n
,存储到这些节点上的数据的有效期都是一致的,记为
T
e
。因此从图
1
可以看出,从
M
1
到
M
k
区间的数据均从
M
k
上存取。比如数据
K
1
,
K
2
,
K
n
。
图1
当新增节点
M
x
时,如图
2
所示。
图2
此时数据
K
1
,
K
2
从新节点
M
x
读取不到的,但节点
M
k
存储了这些数据,我们需要做的就是将这些数据迁移到新节点
M
x
。
具体做法是:将新加入的节点
M
x
标记为
N
(
New
)状态,表示该节点是新增的。在
N
状态下读取数据
K
1
的步骤为:
1)
从
M
x
读取数据,如果读取得到,则返回,否则进行
2
);
2)
从
M
k
读取数据,如果读取不到,则返回,否则进行
3
);
3)
将读取到的数据
K
1
写入
M
x
;
4)
将
K
1
从
M
k
删除;
在
N
状态下,不断进行上面的
4
个步骤
因为数据的有效期是
T
e
,所以在经过
T
e
时间后,
M
k
上的数据随之自动失效了,此时将
M
x
标记为
O
(
Old
)状态,在
O
状态下,如果读取不到数据也立即返回,无需再次到它下一个节点尝试读取。