哨兵与集群
主从同步¶
主从同步默认采用异步复制,主节点写入完成后,立刻返回成功
一致性考量:可以通过执行 wait n ex 来等待至少 n 个从节点确认后,再返回成功(multi 和 lua 中不允许阻塞,立刻返回当前的确认数)
单节点的 Redis 并发能力有上限,通过主从集群实现读写分离
全量同步¶
在从节点新加入时触发。
-
replid:用于标志同一个数据集,归属于同一个 master 的 slave 会继承属于这个 master 的 replid
如果在同步启动时,主节点发现从节点具有相同的 replid,说明不是建立初始连接,不会进行 RDB 的传递,通过 repl_baklog 同步数据
- offset:分别存在于 master 和 slave 中,用于记录 repl_baklog 的同步差异
全量同步时,在 RDB 从生成到发送完成之间的增量数据,通过 repl_baklog 缓冲区进行记录
增量同步¶
从节点发来 psync replid offset 后可以判断需要进行增量同步,主节点从命令日志中获取 offset 之后的数据,发送给从节点进行同步
哨兵模式(Sentinel)¶
Redis 哨兵基于 sentinel.conf 配置文件,作为独立的进程运行,一般部署的哨兵进程数 >= 3
哨兵机制用于实现主从集群的自动故障恢复(监控集群状态,更换 master)
监控机制¶
哨兵基于心跳检测服务状态,每隔 1 秒向集群的每个实例发送 ping 消息(consul 的服务健康检查也是 consul-server 主动定期向 client agent 发送 tcp 探测)
- 主观下线:某个哨兵发现某个实例未在规定时间内响应 pong,则认为该实例主观下线
- 客观下线:超过指定数量的哨兵都认为某个实例主观下线(quorum 一般为哨兵实例数的一半)
选主规则¶
当 master 客观下线后,哨兵需要选主
- 先判断主从节点断开时间长短,断开时间(可配置)超过指定值的从节点被排除
- 判断 slave-priority,越小越高
- 判断 slave 的 offset,越大则优先级越高
- 上述一样,则根据 slave-id 选择
脑裂问题¶
主节点和(从节点和哨兵)处在不同的网络分区,使 sentinel 无法感知主节点的存在,从而在 slave 中选举出了一个 master ,此时就存在两个 master,且客户端还在向原来的主节点写入数据。
当网络恢复后,客户端写入的 master 会被哨兵降为从节点,此时再从新的 master 同步数据时,其原有内容会被清空,导致数据丢失。
解决方案:
- 配置 min-replicas-to-write 1 :如果 master 没有从节点,则拒绝客户端请求
- 配置 min-replicas-max-lag 10:当从节点延迟超过 10s ,则主节点拒绝写入
- 这个值设置的过大,会降低一致性,设置的过小,则会导致主节点频繁拒绝写,降低可用性
- sentinel 方面,提高 quorum 投票数量的阈值,减少误判
分片集群(Cluster)¶
与专注于 Redis 主从架构的哨兵机制不同,分片集群是一个无中心架构(No Master Node)
当使用 Lua 脚本时,需要保证一次执行的脚本中的 key 都唯一同一个节点中
- 水平增加数据的存储量
- 提高写操作的并发能力
路由规则¶
分片集群通过 CRC16 计算 Key 的 hash 值(可以通过 {} 来规定计算的 Key 的部分);通过 bitmap 存储 16384 个 hash 槽,每个 master 节点可以映射到其中的多个槽中。
在路由数据时,Redis 客户端连接任意一个 master 节点,最后消息都可以被转发到正确的节点中。
故障恢复¶
每个主从单元的主节点会持续向集群中的其他主节点发送 ping 消息,当规定时间内没有收到 pong 响应,则这个节点被标记位主观下线。当被半数以上的主节点标记为主观下线时,这个节点会被标记为客观下线。
这里的 ping 和 pong 涉及到信息的交换,包括主观下线情况和槽的分配信息
此后,这个下线的主节点的从节点会开始基于 raft 算法的选举:
- 每个从节点广播一条 CLUSTER_TYPE_FAILOVER_AUTH_REQUEST 消息,要求所有收到消息,且没有投过票的主节点返回 CLUSTER_TYPE_FAILOVER_AUTH_ACK
- 获得的选票数大于集群主节点的一半时,从节点上位,并开始广播 ping