1.哈希取余
通过一个哈希函数得到某一个数字,然后根据数字找到相应的服务器。
经典的哈希函数:用key对节点数(3)取余
容易产生的问题:扩展代价大,增加删除节点需要对所有数据重新洗牌。
2.一致性哈希
一致性 hash 算法本质上也是一种取模算法;
不过,不同于上边按服务器数量取模,一致性 hash 是对固定值 2^32 取模;
2.1一致性哈希算法
1.hash 环
我们可以将这所有的点组成一个圆环
2. 服务器映射到 hash 环
在对服务器进行映射时,使用hash(服务器ip)% 2^32,即:
使用服务器 IP 地址进行 hash 计算,用哈希后的结果对2^32取模,结果一定是一个 0 到2^32-1之间的整数;
而这个整数映射在 hash 环上的位置代表了一个服务器,依次将node0、node1、node2三个缓存服务器映射到 hash 环上;
3.对象 key 映射到服务器
在对对应的 Key 映射到具体的服务器时,需要首先计算 Key 的 Hash 值:hash(key)% 2^32;
注:此处的 Hash 函数可以和之前计算服务器映射至 Hash 环的函数不同,只要保证取值范围和 Hash 环的范围相同即可(即:2^32);
将 Key 映射至服务器遵循下面的逻辑:
从缓存对象 key 的位置开始,沿顺时针方向遇到的第一个服务器,便是当前对象将要缓存到的服务器;
使用该算法扩缩容只需要移动相邻的节点区间就行,不需要移动所有节点。
2.2带虚节点的一致性哈希算法
当节点过少时,可能出现部分节点压力很大的情况。即节点分布不均匀而造成数据倾斜问题
针对上述问题,引入虚拟服务器的概念。
即将每台物理服务器虚拟为一组虚拟服务器,将虚拟服务器放置到哈希环上,如果要确定对象的服务器,需先确定对象的虚拟服务器,再由虚拟服务器确定物理服务器。
即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点,一个实际物理节点可以对应多个虚拟节点,虚拟节点越多,hash环上的节点就越多,缓存被均匀分布的概率就越大,hash环倾斜所带来的影响就越小,同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射。具体做法可以在服务器ip或主机名的后面增加编号来实现,加入虚拟节点以后的hash环如下:
引入虚节点后数据分布存储流程:
v1-6为虚节点,s1-3为实际节点
3.哈希槽
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
使用哈希槽的好处就在于可以方便的添加或移除节点。
当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。