- 问题的来源:Redis集群和其他模式的最大区别是采用了数据拆分的设计,数据分布第一个想到的就是hash取模,但小规模Redis集群只有6台机器,3主3从,如果以3为模很可能会导致分布不均,扩容缩容时也很难办,肯定不能所有key全部重新取模迁移,也不像Java HashMap rehash时固定扩大两倍可以减少迁移key的数量。
hash一致性
- 扩缩容的问题在于要有序且避免key过多迁移,所以提出了hash一致性的hash环,环上2^32个节点,节点平均分布在服务器里,例如4台服务器初始化时,各服务器分配的节点分别是0 ~ 1073741823,1073741824 ~ 2147483647,2147483648 ~ 3221225471,3221225472 ~ 4294967295。
- 扩容:其实就是把其中一个服务器拆出来一半移到新增服务器,但这样数据又不均了,扩容时只有增加为两倍服务时(也就是每个服务器都拆一半出来)才会达到理想的数据分布平衡。
- 虚拟节点:服务器少时数据还会出现分布不均,所以出现了虚拟节点,每一个真实节点虚拟出n倍的虚拟节点分布在环上,按正常规则收录数据,只是节点块分的更细了,比如之前0 ~ 1073741823,现在就要再细分n块分布到各个服务器上,理论上虚拟出来的节点越多,分布越均匀。
Redis集群
- Redis集群和hash一致性类似,增加了虚拟槽的概念,范围是0~16383(据说是作者认为这个范围就够用了),每个槽里又是对应很多具体key,均匀分布在集群主节点上,Redis数据访问、迁移时都会先定位到具体槽,取模也就按槽数量取了,如3主节点平均分布后为0 ~ 5460、5460 ~ 10922、10923 ~ 16383。
- 添加新节点时默认新节点没有槽位,只需要把之前各节点分出一部分给新节点,最后达到槽位平衡即可,而且Redis提供在线迁移,保证迁移过程正常使用。