32淘汰和集群

缓存淘汰和过期删除

过期删除策略和内存淘汰策略有什么区别?

区别:

  • 内存淘汰策略是在内存满了的时候,redis 会触发内存淘汰策略,来淘汰一些不必要的内存资源,以腾出空间,来保存新的内容
  • 过期键删除策略是将已过期的键值对进行删除,Redis 采用的删除策略是惰性删除+定期删除。

内存淘汰策略

image-20251120154027582

介绍一下Redis过期删除策略

Redis采用惰性删除+定期删除的组合策略,核心目标是在合理消耗CPU资源和避免内存浪费后之间找到最优平衡

(1)惰性删除

流程步骤

键过期并不会立即删除,仅在访问/修改该键前,通过db.c文件中的expiredIfNeeded函数检查是否过期

若已经过期则根据lazyfree_lay_expire(Redis4.0+)配置,选择同步删除或异步删除,并返回null给客户端

优缺点

避免在大量键同时过期时,占用过多CPU资源而拖慢Redis的正常使用.惰性删除能分散压力

若过期键长期不被访问,仍会占用内存,这就依赖于定期删除了

(2)定期删除

每次从设置了过期时间的键中随机抽取20个,删除其中过期的键

若过期键占比大于25%,则重复抽查直到小于等于25%,等待下一次执行

由redis.config中的hz配置中控制执行间隔,默认100ms执行一次

image.png

Redis缓存失效会不会立即删除,为什么?

不会,Redis的缓存删除策略是惰性删除+定期删除混合使用为了

防止缓存短时间大量失效而造成的批量删除场景,会占用大量CPU资源进而影响Redis的响应时间和吞吐量,

集群

主从

#Redis主从同步中的增量和完全同步怎么实现?

完全同步

完全同步发生在以下几种情况:

  • 初次同步:当一个从服务器(slave)首次连接到主服务器(master)时,会进行一次完全同步。
  • 从服务器数据丢失:如果从服务器数据由于某种原因(如断电)丢失,它会请求进行完全同步。
  • 主服务器数据发生变化:如果从服务器长时间未与主服务器同步,导致数据差异太大,也可能触发完全同步。

增量同步

触发条件

Slave断线重连同步且断线期间repl_backlog仍正常保存Slave断开时offset之后的命令未被覆盖

流程拆解

身份校验:Slave重连后发psync replid offset,Master验证replid一致且repl_backlog中offset之后的命令未被覆盖.

增量命令

推送从repl_backlog中定位到Slave提供的offset,提取该位置之后的所有命令,通过TCP连接以流的形式持续推送给Slave,同时更新Slave的offset记录

Slave端接收命令按顺序执行,每执行完一批命令就向Master反馈最新的offset,直到offset版本与Master的一致

介绍一下repl_backlog和offset

(1)repl_backlog

本质上是固定大小的环形缓冲区,默认大小是1MB

主要用于记录主节点接收到的写命令可以应用于增量同步和全量同步时的数据增量

(2)offsetoffset

是一个偏移量,用于关联repl_backlog中写命令的位置

主节点维护着一个master_repl_offset,从节点维护一个slave_repl_offset都记录自己当前关联在repl_backlog中的版本

主节点和从节点版本的差距不能超过一个repl_backlog的差距

redis主从和集群可以保证数据一致性吗 ?

redis 主从和集群在CAP理论都属于AP模型,即在面临网络分区时选择保证可用性和分区容忍性,而牺牲了强一致性。这意味着在网络分区的情况下,Redis主从复制和集群可以继续提供服务并保持可用,但可能会出现部分节点之间的数据不一致

image.png

哨兵机制原理是什么?

哨兵(***Sentinel***)机制,它的作用是实现主从节点故障转移。它会监测主节点是否存活,如果发现主节点挂了,它就会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端。

哨兵节点主要负责三件事情:监控、选主、通知

哨兵机制的选主节点的算法介绍一下

当redis集群的主节点故障时,Sentinel集群将从剩余的从节点中选举一个新的主节点,有以下步骤:

  1. 故障节点主观下线

    每一个Sentinel节点会定时对redis集群的所有节点发心跳包检测节点是否正常。如果一个节点在down-after-milliseconds时间内没有回复Sentinel节点的心跳包,则该redis节点被该Sentinel节点主观下线。

  2. 故障节点客观下线

    该Sentinel节点会询问其他Sentinel节点,如果Sentinel集群中超过quorum数量的Sentinel节点认为该redis节点主观下线,则该redis客观下线。

  3. Sentinel集群选举Leade

    一个Sentinel节点确认redis集群的主节点主观下线后,会请求其他Sentinel节点要求将自己选举为Leader。被请求的Sentinel节点如果没有同意过其他Sentinel节点的选举请求,则同意该请求(选举票数+1),否则不同意。

    4.Sentinel Leader决定新主节点

当Sentinel集群选举出Sentinel Leader后,由Sentinel Leader从redis从节点中选择一个redis节点作为主节点:

  1. 过滤故障的节点
  2. 选择优先级slave-priority最大的从节点作为主节点,如不存在则继续
  3. 选择复制偏移量(数据写入量的字节,记录写了多少数据。主服务器会把偏移量同步给从服务器,当主从的偏移量一致,则数据是完全同步)最大的从节点作为主节点,如不存在则继续
  4. 选择runid(redis每次启动的时候生成随机的runid作为redis的标识)最小的从节点作为主节点

分片

什么是集群

Redis分片集群是Redis官方提供的分布式解决方案,通过将数据分散到多个节点,解决了单机Redis在内存容量、计算能力和可用性方面的限制。该模式采用去中心化架构,无需依赖外部协调组件如ZooKeeper或Sentinel(虽然可以配合使用)。

核心机制解析

1. 哈希槽机制

  • Redis Cluster使用16384个固定哈希槽作为数据分布的映射处理
  • 一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中,具体执行过程分为两大步:
    • 根据键值对的 key,按照 CRC16 算法计算一个 16 bit 的值。
    • 再用 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。
  • 键到槽的映射:slot = CRC16(key) % 16384
  • 16384这个数字的选择很精妙:足够小以保证节点间心跳包不会过大(每个包携带位图表示槽分配),又足够大以支持最多1000个节点的集群规模

只有当16384个槽全部分配完毕,Redis Cluster才会进入正常工作状态.否则会报错

平均分配:使用cluster create命令创建集群时,Redis自动平均分配

手动分配:灵活可控,性能强的节点可以分配更多槽

2. 高可用设计

  • 主从架构:每个主节点至少有一个从节点,用于数据备份和故障转移

  • 去中心化通信:通过Gossip协议实现节点间高效、可靠的信息交换

    协议内容节点状态:

    节点在线情况,角色

    哈希槽归属:明确哪些节点负责哪些哈希槽

    主从映射:记录Slave对应哪个Master

    • 节点定期随机选择其他节点交换信息
    • Redis Cluster节点通信不依赖单一中心组件,每个节点都能主动发起信息交换,没有核心的指挥中心,避免中心节点故障导致的整个集群通信瘫痪,不过也有状态同步的微小延迟.

3. 故障转移机制

  • 节点互相监控,当多数主节点认为某节点不可达时,标记为客观下线(PFAIL→FAIL)
  • 从节点通过类Raft投票机制选举新主,优先考虑:
    1. 数据复制偏移量(offset)最大的从节点
    2. 运行ID字典序最小的节点
  • 整个过程通常在几秒内完成,大幅降低服务中断时间

4. 客户端交互

  • 客户端维护槽到节点的映射缓存
  • 当请求错误节点时,返回MOVED重定向(永久重定向)或ASK重定向(临时重定向,用于槽迁移中)
  • 智能客户端会自动更新本地缓存,优化后续请求路由

优势分析

  1. 线性扩展能力:通过增加节点,几乎线性提升集群容量和吞吐量
  2. 高可用保障:内置故障检测和自动转移,无需额外组件
  3. 去中心化设计:无单点故障,避免了传统中心化协调器的瓶颈
  4. 灵活的数据分布:可根据节点性能分配不同数量的哈希槽
  5. 客户端缓存优化:减少重定向开销,提高访问效率
  6. 平滑扩容/缩容:支持在线迁移哈希槽,服务不中断

局限与挑战

  1. 跨槽操作受限
    • 无法执行跨多个哈希槽的事务
    • 多键操作(如MGET)要求所有键在同一个槽
    • 可通过哈希标签(例如{user1000}.profile{user1000}.orders共享相同哈希标签)解决部分场景
  2. 复杂性代价
    • 集群部署、监控、故障诊断比单机模式复杂
    • 需要专门的运维知识和工具支持
  3. 数据均衡挑战
    • 热点数据可能集中在少数槽,导致负载不均
    • 需要手动干预重新分配槽或使用哈希标签优化
  4. 网络分区风险
    • 在严重网络分区情况下,可能面临脑裂问题
    • 需要合理配置cluster-node-timeout等参数平衡可用性和一致性

✅ 一句话核心结论

**”脑裂 = 网络分区导致集群分裂,多个节点同时自称主节点 → *数据混乱!* 解决方案:*用多数派原则(Quorum)+ 合理超时*,让 Redis Sentinel/Cluster 自动避免脑裂。”**

Redis 如何解决脑裂?(3 个关键配置)

✅ 方案 1:Redis Sentinel 的 Quorum(法定人数)(核心!)

1
2
3
4
# sentinel.conf 配置示例
sentinel monitor mymaster 10.0.0.1 6379 2 # quorum=2(需2个Sentinel同意)
sentinel down-after-milliseconds mymaster 30000 # 网络延迟阈值(ms)
sentinel failover-timeout mymaster 180000 # 故障转移超时
  • 原理:

    “故障转移 必须获得多数 Sentinel 同意(如 3 个 Sentinel 中需 2 个同意)→ 网络分区时,少数派 Sentinel 无法触发选举 → 避免脑裂。”

💡 为什么有效

  • 网络分区后,Sentinel 分成两组:A组(2个)和 B组(1个)
  • A组能触发选举(因 quorum=2),B组不能 → 只有 A组 生成新 Master
  • 原 Master(在 B组)无法被选举 → 不会产生第二个 Master

✅ 方案 2:Redis Cluster 的 cluster-require-full-coverage(核心!)

1
2
3
4
# redis.conf 配置
cluster-require-full-coverage no # 默认值:no(可关闭)
# 改为:
cluster-require-full-coverage yes # 强制要求集群完整
  • 原理:

    “当 节点数 < 总节点数的一半 时,集群拒绝服务(不提供写操作)→ 防止小集群继续工作导致脑裂。”

💡 为什么有效

  • 假设集群有 5 个节点,网络分区成 2+3 两组
  • 2 个节点组无法达到 5/2=3 节点的法定要求 → 自动拒绝服务
  • 3 个节点组正常工作 → 只有一个 Master(无脑裂)

Redis 官方建议
“在生产环境必须开启 cluster-require-full-coverage yes!”


✅ 方案 3:合理设置超时时间(避免误判)

配置项 推荐值 作用
down-after-milliseconds 30000(30秒) 网络延迟超过此值才判宕机
failover-timeout 180000(3分钟) 故障转移超时,避免反复切换

💡 为什么重要

  • 短超时(如 5秒)→ 网络抖动触发误判 → 脑裂风险↑
  • 长超时(如 30秒)→ 等待网络恢复 → 减少误判
    (实测:30秒是网络抖动的典型恢复时间)
误区 事实 为什么
“Redis 会自动解决脑裂” 错误! 需手动配置 quorum/cluster-require-full-coverage Redis 本身不默认开启,需主动配置
“脑裂只发生在 Sentinel” 错误! 也发生在 Redis Cluster 两种模式都可能脑裂
“关掉 Sentinel 就能避免脑裂” 错误! 无 Sentinel 时脑裂更严重 无故障转移机制,数据混乱更彻底
“设置 quorum=1 最安全” 错误! quorum=1 会放大脑裂风险 1 个 Sentinel 就触发选举 → 网络抖动即脑裂

end


32淘汰和集群
http://example.com/2025/11/19/32淘汰和集群/
作者
無鎏雲
发布于
2025年11月19日
许可协议