集群模式
Redis Cluster的设计目标:
- 高性能:高性能是Redis的看家本领,增加集群后不能对性能产生太大影响
- 水平扩展:必须具备水平扩展
- 高可用:Cluster集群也应该具备Sentinel的监控、提醒、自动故障转移等功能
数据分区方案
为了使集群能够水平扩展,首先要解决 如果将整个数据集按照一定的规则分配到多个节点上,常有的数据分区方法有:
普通哈希分区
普通哈希分区比较简单,就是根据规定的哈希函数将数据哈希到指定的节点上。一般哈希函数采用取余法哈希
function hash(key) {
teturn key % 3
}
当写数据的时候, 根据哈希函数写到对应的节点中,读数据的时候先计算出数据在哪个节点,然后再去对应的节点去取。当节点数固定的时候,这种数据分区方案没有问题,当增加一个节点或删除一个节点的时候,取余的哈希函数的分母会改变,导致之前分配的数据分区大量改变,并造成大量的数据获取不到
一致性哈希分区
为了解决普通的哈希分区的缺点,提出了一致性哈希的概念。一致性哈希的核心原理:将key和节点都通过哈希函数映射到2^32次方的环上,一次性哈希尽最大限度的解决了节点改变带来的数据不一致问题
虚拟槽分区
Cluster采用的这是这种分区方式。虚拟槽分区使用哈希空间,使用分散度良好的哈希函数把所有的数据映射到一个固定的范围内的整数集合,整数定义为槽(slot),Redis Cluster 的槽范围是 0 ~ 16383, 槽是集群内的数据管理和迁移的基本单位。 每个节点负责一定数量的槽。 计算公式:
CRC16(key) & 16383
每一个节点负责维护一部分槽及槽所映射的键值数据
采用 哈希虚拟槽分区 的特性:
- 解耦了数据和节点直接按的关系,简化了节点的扩容和收缩的难度
- 节点自身来维护槽的映射关系,不需要客户端或代理来维护槽分区的元数据
- 支持节点、槽、键之间的映射查询
节点增加和删除
采用Cluster的集群方案,当节点增加和删除时,集群如何保持高可用/
- 增加节点
当增加一个节点时,只需把其它节点的某些哈希槽 移到新的节点 即可
- 移除节点
当移除一个节点时,只需把该节点上的哈希槽 移到其它节点 即可
数据迁移a
槽迁移
在迁移的中间状态下,槽 1、2、3 在 MasterA 节点的状态为 MIGRATING(迁移), 在 MasterB 节点的状态为:
IMPORTING(入口)
IMPORTING(入口),状态是被迁移的槽在目标节点中出现的一种状态,准备迁移从A到B的时候,被迁移的槽的状态首先变为 IMPORTING(入口)
此时不刷新 node的映射关系
键空间的迁移
在满足迁移的条件下:通过命令将 slot1, slot2, slot3 中的键空间从A 迁移到B。迁移过程大致如下:
- MasterA 节点执行DUMP命令, 序列化要迁移的key,并将数据发送给 MasterB
- MasterB 节点接受到要迁移的序列化key之后执行 RESTORE 命令反序列化key,并保存
- MasterA节点执行 DEL命令 删除已经迁移的key
迁移完成后,刷新 node 的映射关系
需要注意的是:MIGRATE(迁移)并不是原子的,a如果MIGRATE出现错误的情况可能会导致如下问题:
- 键空间在两个节点都存在
- 键空间只存在第一个节点
1.为什么不用一致性哈希,而用槽哈希分区
Redis使用的是crc16的简单算法,虽然可能没有一致性哈希灵活,但实现比较简单,节点的增加和删除都比较方便
- 节点增加和删除的过程中,数据会不会丢失
节点在数据迁移的时候数据会有备份,不会丢失