主从复制
在 Redis 主从集群中,一个主节点(Master)负责处理客户端的读写请求,而多个从节点(Slave)则负责复制主节点的数据,并对外提供读取服务——解决高并发问题。
-
主节点(Master):
- 主节点是集群中的核心节点,负责处理客户端的写入请求(如写入操作、更新操作等)。主节点维护系统的主要数据副本,并负责将写入的数据复制到所有的从节点上。
-
从节点(Slave):
- 从节点是主节点的备份节点,负责复制主节点的数据,并对外提供读取服务。从节点通过异步复制的方式从主节点同步数据,并保持与主节点的数据一致性。从节点通常用于处理客户端的读取请求(如查询操作、读取操作等),以分担主节点的读取负载。
主从数据同步原理
全量同步流程:
- 从节点请求主节点同步数据(replication id、 offset )
- 主节点判断是否是第一次请求,是第一次就与从节点同步版本信息(replication id和offset)
- 主节点执行bgsave,生成rdb文件后,发送给从节点去执行
- 在rdb生成执行期间,主节点会以命令的方式记录到缓冲区(一个日志文件)
- 把生成之后的命令日志文件发送给从节点进行同步
增量同步流程:
- 从节点请求主节点同步数据,主节点判断不是第一次请求,不是第一次就获取从节点的offset值
- 主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步
哨兵模式
哨兵(Sentinel)机制来实现主从集群的自动故障恢复——解决高可用问题。哨兵的结构和作用如下:
- 监控:Sentinel 会不断检查您的master和slave是否按预期工作
- 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
- 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
服务状态监控:
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
- 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
- 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
哨兵选主规则:
- 首先判断主与从节点断开时间长短,如超过指定值就排该从节点
- 然后判断从节点的slave-priority值,越小优先级越高
- 如果slave-priority一样,则判断slave节点的offset值,越大优先级越高
- 最后是判断slave节点的运行id大小,越小优先级越高。
脑裂
脑裂(Split Brain)是一种可能发生的问题,它指的是在网络分区或故障发生时,导致集群中的不同部分之间失去了联系,每个部分都认为自己是整个集群的唯一有效部分,从而导致数据不一致和服务不可用的情况。
在脑裂的情况下,Redis 哨兵集群中可能出现以下情况之一:
-
多个主节点:在网络分区发生时,如果哨兵节点无法互相通信,可能会导致出现多个主节点。每个部分的哨兵节点都会尝试选举新的主节点,导致整个集群中出现多个主节点,这将导致数据不一致和服务不可用。如图:
-
部分节点失效:在网络分区或节点故障发生时,可能会导致部分哨兵节点失去联系或认为其他节点失效。这可能会导致误将正常的节点标记为失效,从而导致服务中断或数据丢失。如图,若将老的master(左边的redis)强制降为Slave,此时这个Slave就会去新的master中去同步数据,将自己的数据清空,也因此丢掉了脑裂过程中(它还作为master)写入的数据。
避免以上情况的发生:
redis中有两个配置参数:
min-replicas-to-write 1 表示最少的salve节点为1个
min-replicas-max-lag 5 表示数据复制和同步的延迟不能超过5秒
分片集群
分片集群(Shared Cluster)的提出主要解决海量数据存储问题和高并发写的问题。使用分片集群可以解决上述问题,分片集群特征:
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点
- master之间通过ping监测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点
分片集群结构-数据读写
Redis 分片集群引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。
读写数据:根据key的有效部分计算哈希值,对16384取余(有效部分,如果key前面有大括号,大括号的内容就是有效部分,如果没有,则以key本身做为有效部分)余数做为插槽,寻找插槽所在的实例