数据存储设计
redis是每个节点只存储全部数据的一部分。
启动后看其中一个主机的配置文件,可见槽怎么分的,谁是主谁是从,自己(myself)是什么角色都有记录。
计算过程
键的桶编号计算方法
// key先经过CRC16函数计算出一个值,再对16384取模
HASH_SLOT = CRC16(key) mod 16384
节点的增减
原则:反正一共就16384份,加节点了,大家都给它匀一点儿,减节点了,大家就把它的分一分。
集群内部通讯设计
各个节点互相通信,保存各个节点中槽的编号数据。
即:每个节点都存储一份:16384的位置分布图。
client 如何命中正确的节点?
原则:client 最多找两次
如果第一次就命中,那么直接处理命令,返回结果。
如果第一次未命中,那么根据位置分布图,返回client这个key正确的节点是哪个,保证client第二次一定能直接请求到。
故障发现
https://blog.csdn.net/tr1912/article/details/81265007
通过ping/pong消息实现故障发现,不需要sentinel
主观下线:
某个节点认为另外一个节点不可用
客观下线:
当半数以上持有槽的主节点都标记某节点主观下线
- 通知集群内所有节点标记故障节点为客观下线
- 通知故障节点的从节点触发故障转移流程
故障恢复
1、资格检查
每个从节点检查与故障主节点的断线时间。断线时间,超过cluster-node-timeout * cluster-slave-validity-factor 取消资格
cluster-node-timeout默认15000ms,cluster-slave-validity-factor默认10,说白了就是把数据太旧的淘汰。
准备选举时间
从节点根据自身复制偏移量设置延迟选举时间,复制偏移量越大延迟越低,越有机会
选举投票
当从节点定时任务检测到达故障选举时间到达后,发起选举,
在集群内广播选举消息,只有持有哈希槽的主节点才能参与投票,获得 N/2+1 的选票胜出。
故障主节点也算在投票数内。
假设集群内节点规模是3主3从,其中有2个主节点部署在一台机器上,当这台机器宕机时,由于从节点无法收集到 3/2+1个主节点选票将导致故障转移失败。
这个问题也适用于故障发现环节。
因此部署集群时所有主节点最少需要部署在3台物理机上才能避免单点问题。
替换主节点
当前从节点取消复制变为主节点。向集群广播自己的pong消息,通知集群内所有的节点当前从节点变为主节点并接管了故障主节点的槽信息。
三种部署方式的优缺点
主从
优点:
- 可以进行读写分离,分担master的读压力
缺点:
- 不具备自动容错与恢复功能,master或slave的宕机都可能导致客户端请求失败,需要等待机器重启或手动切换客户端IP才能恢复
- 主从复制是异步的,存在丢失数据的可能
- 难以支持在线扩容,Redis的容量受限于单机配置
哨兵
优点:
- 在主从的优点基础上,可以自动故障转移
缺点:
- 难以在线扩容、Redis的容量受限于单机配置、丢失数据依然存在
- 需要额外的资源来部署sentinel
集群
优点:
- 可以自动故障转移(和哨兵的玩法不一样)
- 可扩容,解决了单机瓶颈
- 不需要额外资源(与哨兵相比)
缺点:
- 丢数据,或者说无法保证数据强一致性的问题依然存在
- 客户端实现复杂
- 批量操作限制,目前只支持具有相同slot值的key执行批量操作
- 事务操作限制,多key分布不同节点时无法使用事务功能