4. Redis哨兵模式
在主从复制我们知道slave节点宕机恢复后可以找master节点同步数据,那master节点宕机就需要另外一种方式了。Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。
4.1. Sentinel的三个作用
1. 监控:Sentinel 会不断检查您的master和slave是否按预期工作
2. 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
3. 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
4.1.1.服务状态监控
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
- 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
- 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线(这时候就需要选取新的master节点了)。quorum值最好超过Sentinel实例数量的一半。
4.1.2.新master选取规则:
一旦发现master故障,sentinel需要在salve中选择一个作为新的master。
- 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
- 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
- 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
- 最后是判断slave节点的运行id大小,越小优先级越高。
4.1.2.故障转移:
选中了其中一个slave为新的master后,就需要进行故障转移:
- sentinel给备选的slave(127.0.0.1 7002)节点发送slaveof no one命令,让该节点成为master
- sentinel给所有其它slave发送slaveof 127.0.0.1 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
- 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
5. Redis分片集群
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
- 海量数据存储问题
- 高并发写的问题
5.1. 分片集群特征:
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点
- master之间通过ping监测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点(根据插槽所属的节点进行转发)
5.2. 散列插槽
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上。数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
- key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
- key中不包含“{}”,整个key都是有效部分
例如:key是num,那么就根据num计算得到的slot值所属哪个节点就转发到哪个节点,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。
思考下面两个问题:
1.Redis如何判断某个key应该在哪个实例?
分片集群将16384个插槽分配到不同的实例,可以根据key的有效部分计算哈希值,对16384取余,余数作为插槽,寻找插槽所在实例即可。
2.如何将同一类数据固定的保存在同一个Redis实例?
这一类数据使用相同的有效部分,例如key都以{typeId}为前缀
5.3. 集群伸缩
# 添加一个节点到集群中(让7001所在的集群添加一个7001的redis实例)
redis-cli --cluster add-node 127.0.0.1:7004 127.0.0.1:7001
# 新增的实例是没有分配插槽的,将部分插槽分配到新插槽
redis-cli --cluster add-node reshared 127.0.0.1:7001
# 不带下面参数,直接执行上面语句,根据控制台提示再填写相关信息,或者在指令之后带上下面的参数
--cluster-from:表示slot目前所在的节点的node ID,多个ID用逗号分隔
--cluster-to:表示需要新分配节点的node ID(貌似每次只能分配一个)
--cluster-slots:分配的slot数量
# 清空插槽
redis-cli --cluster reshard 127.0.0.1:7004
# 下线节点
redis-cli --cluster del-node 127.0.0.1:7004 node ID
del-node后面跟着slave节点的 ip:port 和node ID
5.4.故障转移
当集群中有一个master宕机,首先是该实例与其它实例失去连接,然后是疑似宕机,最后是确定下线,自动提升一个slave为新的master:
利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。
手动的Failover支持三种不同模式:
- 缺省:默认的流程,如图1~6
- force:省略了对offset的一致性校验
- takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见