Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:
监控:Sentinel会不断检查您的master和slave是否按预期工作
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的mater为主
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
RedisTemplate的哨兵模式
在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。
分片集群结构
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
海量数据存储问题
高并发写的问题
使用分片集群可以解决上述问题,分片集群特征:
集群中有多个master,每个master保存不同数据
每个master都可以有多个slave节点
master之间通过ping检测彼此健康状态
客户端请求可以访问集群任意节点,最终都会被转发到正确节点
散列插槽
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
key中包含“{}”,且“{}”中至少包含1个字符,“{}”中的部分是有效部分
key中不包含“{}”,整个key都是有效部分
例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果slot值。
不同的key被分配到不同的插槽。
Redis如何判断某个key应该在哪个实例?
将16384个插槽分配到不同的实例
根据key的有效部分计算哈希值,对16384取余
余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定地保存在同一个Redis实例?
这一类数据使用相同的有效部分,例如key都以{typeId}为前缀
集群伸缩
添加一个节点到集群
Redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看:
比如,添加节点的命令:
向集群中添加一个新的master节点,并向其中存储 num = 10
需求:
启动一个新的redis实例,端口为7004
添加7004到之前的集群,并作为一个master节点
给7004节点分配插槽,使得num这个key可以存储到7004实例
通过命令查看7004的插槽位
故障转移
当集群中有一个master宕机会发生什么?
1、首先是该实例与其它实例失去连接
2、然后是疑似宕机:
3、最后是确定下线,自动提升一个slave为新的master
数据迁移
利用cluster failover命令可以让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:
手动的Failover支持三种不同模式:
缺省:默认的流程
force:省略了对offset的一致性校验
takeover:直接执行第5步,忽略数据一致性、忽略master状态和其它master的意见
在7002这个slave节点执行手动故障转移,重新夺回master地位
步骤如下:
1、利用redis-cli连接7002这个节点
2、执行cluster failover命令