Redis 集群
Redis 3.0 开始,Redis 官方提供了集群的解决方案:Redis Cluster,Redis Cluster 通过分片来进行数据管理,提供了复制和故障转移等功能,比较方便地进行横向扩展。
集群安装
使用 cluster meet <ip> <port>
命令,可以让当前节点与 ip 和 port 所指定的节点进行握手,成功后可将新节点添加到当前节点当前所在的集群中。
槽与 Redis 实例的映射
Redis Cluster 采用了虚拟槽分区,有 16384 个槽(为什么是16384?),每个键值对都属于一个槽,槽的位置通过计算 key 的 CRC16 的值再对 16384 取模获得。Cluster 还允许用户强制某个 key 挂在特定槽位上,通过在 key 字符串里面嵌入 tag 标记,这就可以强制 key 所挂在的槽位等于 tag 所在的槽位。
使用 cluster addslots xxx,xxx
命令为节点分配槽位,只有当 16384 个槽都分配完毕,Redis 集群才能正常工作。
复制与故障转移
Master 用于处理槽位,Slave 与 Master 进行主从同步数据。当 Master 下线,Slave 代替主节点继续处理请求,主从节点之间并没有读写分离, Slave 只用作 Master 宕机的高可用备份。
Redis Cluster 可以为每个主节点设置若干个从节点,单主节点故障时,集群会自动将其中某个从节点提升为主节点,保障集群正常工作。
如果某个主节点没有从节点,那么当它发生故障时,集群将完全处于不可用状态。
故障转移流程
当一个 Slave 发现自己的 Master 进入下线状态后,从节点将开始对下线的主节点进行故障转移:
- 从下线的 Master 的 Slave 节点列表选择一个节点成为新主节点;
- 新主节点会撤销所有对已下线主节点的 slot 指派,并将这些 slots 指派给自己。
- 新的主节点向集群广播一条 PONG 消息,这条 PONG 消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽;
- 新的主节点开始接收处理槽有关的命令请求,故障转移完成。
选举 Master 流程
- 集群的配置纪元 +1,是一个自增计数器,初始值 0 ,每次执行故障转移都会 +1;
- 检测到主节点下线的从节点向集群广播一条
CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST
消息,要求所有收到这条消息、并且具有投票权的主节点向这个从节点投票; - 如果这个主节点尚未投票给其他从节点,那么主节点将向要求投票的从节点返回一条
CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
消息,表示这个主节点支持从节点成为新的主节点; - 参与选举的从节点都会接收
CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
消息,如果收集到的票>= (N/2) + 1
支持,那么这个从节点就被选举为新主节点; - 如果在一个配置纪元里面没有从节点能收集到足够多的支持票,那么集群进入一个新的配置纪元,并再次进行选举,直到选出新的主节点为止。
定位 key 所在实例
重新分配哈希槽
Redis Cluster 提供了重定向机制:客户端将请求发送到实例上,这个实例没有相应的数据,该 Redis 实例会告诉客户端将请求发送到其他的实例上。
-
MOVED 错误
MOVED 错误(负载均衡,数据已经迁移到其他实例上):当客户端将一个键值对操作请求发送给某个实例,而这个键所在的槽并非由自己负责的时候,该实例会返回一个 MOVED 错误指引转向正在负责该槽的节点,客户端还会更新本地缓存,将该 slot 与 Redis 实例对应关系更新正确。
-
ASK 错误
如果请求的 key 在当前节点找到就直接执行命令,否则时候就需要 ASK 错误响应了,槽部分迁移未完成的情况下,如果需要访问的 key 所在 Slot 正在从从 实例 1 迁移到实例 2,实例 1 会返回客户端一条 ASK 报错信息:客户端请求的 key 所在的哈希槽正在迁移到实例 2 上,你先给实例 2 发送一个 ASKING 命令,接着发发送操作命令。
ASK
错误指令并不会更新客户端缓存的哈希槽分配信息,MOVED
指令则更新客户端本地缓存,让后续指令都发往新实例。