简介
Redis集群是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。Redis集群不需要sentinel哨兵也能完成节点移除和故障转移的功能,其基本架构如下
集群原理
Redis集群通过数据分区来实现数据的分布式存储,通过自动故障转移实现高可用。
分配哈希槽
Redis集群中引入了哈希槽的概念,Redis集群有16384个哈希槽,进行set操作时每个key会通过CRC16校验后再对16384取模来决定放置在哪个槽。Cluster中的每个节点负责一部分hash槽(hash slot)
例如集群中存在三个节点信息如下
- 节点master1包含0到5500号哈希槽;
- 节点master2包含5501到11000号哈希槽;
- 节点master3包含11001到16384号哈希槽。
当执行set key value时,CRC16(key) % 16384 = 777那么这个可以就会被分配到节点A上。
节点之间如何通信
Redis集群中的数据是通过哈希槽的方式分开存储的,集群中每个节点都需要知道其他所有节点的状态信息,包括当前集群状态、集群中各节点负责的哈希槽、集群中各节点的master-slave状态、集群中各节点的存活状态等。Redis集群中节点之间通过建立TCP连接,使用gossip协议来传播集群的信息。
gossip协议(gossip protocol)是基于流行病传播方式的节点或者进程之间信息交换的协议。Redis集群中各节点之间传递消息就是基于gossip协议,最终达到所有节点都会知道整个集群完整的信息。gossip协议有4种常用的消息类型:PING、PONG、MEET、FAIL。
- Meet通过cluster meet ip port命令,已有集群的节点会向新的节点发送邀请,加入现有集群。
- Ping节点每秒会向集群中其他节点发送 ping 消息,消息中带有自己已知的两个节点的地址、槽、状态信息、最后一次通信时间等。
- Pong节点收ping消息后会回复pong消息,消息中同样带有自己已知的两个节点信息。
- Fail节点ping不通某节点后,会向集群所有节点广播该节点挂掉的消息。其他节点收到消息后标记已下线。
故障转移
Redis集群的故障转移和哨兵的故障转移类似,但是Redis集群中所有的节点都要承担状态维护的任务。
故障发现Redis集群内节点通过ping/pong消息实现节点通信,集群中每个节点都会定期向其他节点发送ping消息,接收节点回复pong 消息作为响应。如果在cluster-node-timeout时间内通信一直失败,则发送节 点会认为接收节点存在故障,把接收节点标记为主观下线(pfail)状态。
当某个节点判断另一个节点主观下线后,相应的节点状态会跟随消息在集群内传播。通过Gossip消息传播,集群内节点不断收集到故障节点的下线报告。当 半数以上持有槽的主节点都标记某个节点是主观下线时。触发客观下线流程。
说明:当故障节点变为客观下线后,如果下线节点是持有槽的主节点则需要在它的从节点中选出一个替换它,从而保证集群的高可用。
故障恢复
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave。Failover的过程需要经过类Raft协议的过程在整个集群内达到一致,其过程如下:
- slave发现自己的master变为FAIL
- 将自己记录的集群currentEpoch加1,并广播Failover Request信息
- 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack
- 尝试failover的slave收集FAILOVER_AUTH_ACK
- 超过半数后变成新Master
- 广播Pong通知其他集群节点
集群伸缩
Redis集群提供了灵活的节点扩容和收缩方案,可以在不影响集群对外服务的情况下,为集群添加节点进行扩容也可以下线部分节点进行缩容。
集群扩容
例如下面一个集群,每个节点对应若干个槽,每个槽对应一定的数据,添加1个节点希望实现集群扩容时,需要通过相关命令把一部分槽和内容迁移给新节点。
操作步骤
1.新节点加入到集群中,可以通过在集群中任何一个客户端执行cluster meet新节点ip:端口,或者通过redis-trib add node添加,新添加的节点默认在集群中都是主节点。
2.迁移数据的大致流程,首先需要确定哪些槽需要被迁移到目标节点,然后获取槽中key,将槽中的key全部迁移到目标节点,然后向集群所有主节点广播槽(数据)全部迁移到了目标节点。或者直接通过redis-trib工具做数据迁移很方便。
集群缩容
集群缩容与扩容非常类似,先把槽和数据迁移到其它节点,再把对应的节点下线。
Redis集群优缺点
优点
- 无中心架构;
- 数据存储在多个节点,节点间数据共享,可动态调整数据分布;
- 高可扩展性,节点可动态添加或删除;
- 高可用性,部分节点不可用时,通过增加Slave做standby数据副本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成Slave到Master转换,
- 降低运维成本,提高系统的扩展性和可用性。
缺点
- Client实现复杂,驱动要求实现SmartClient,缓存slots mapping 信息并及时更新提高了开发难度。
- 节点会因为某些原因发生阻塞(阻塞时间大于 clutser-node-timeout),被判断下线。
- 数据通过异步复制,无法保证数据的强一致性。
- 多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容易出现相互影响的情况。
Redis集群实现其他方案
除了官方提供了Redis集群方案,我们还可以通过其他方式来实现Redis集群,例如Twemproxy、Codis等,关于这些方案的实现原理,后续文章在具体讲解。
总结
本文讲解了Redis高可用架构之集群方案,如有疑问请随时反馈。
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。