redis怎么做rehash的

文章目录

在Redis中,rehash(重新哈希)是哈希表(如字典dict,Redis中存储键值对的核心结构)调整容量以维持高效查询的过程。当哈希表中的元素数量过多或过少时,通过rehash调整哈希表大小,平衡空间利用率和查询效率。

一、为什么需要rehash?

哈希表的性能依赖于负载因子 (load factor):
负载因子 = 哈希表已保存的节点数量 / 哈希表的大小

  • 若负载因子过大(元素过多):哈希冲突概率增加,查询、插入等操作效率下降(最坏情况从O(1)退化为O(n))。
  • 若负载因子过小(元素过少):哈希表空间浪费严重。

因此,Redis需要通过rehash动态调整哈希表大小,使负载因子维持在合理范围(通常0.1 ~ 5之间)。

二、Redis哈希表的基础结构

Redis的字典(dict)底层由两个哈希表 (ht[0]和ht[1])组成,每个哈希表包含:

  • table:数组(哈希桶),每个元素指向一个链表(解决哈希冲突)。
  • size:哈希表大小(table数组的长度,总是2的幂,便于位运算)。
  • used:已存储的节点数量。

平时仅使用ht[0],ht[1]仅在rehash时临时使用。

三、rehash的完整流程

Redis的rehash是渐进式(incremental) 的,避免一次性迁移所有元素导致的性能阻塞(尤其在数据量大时)。步骤如下:

1. 触发rehash(确定新容量)

当满足以下条件时,触发rehash:

  • 扩容:
  • 负载因子 ≥ 1,且Redis没有执行BGSAVE/BGREWRITEAOF(后台持久化);
  • 或负载因子 ≥ 5(无论是否在持久化,强制扩容)。

新容量为ht[0].size的最小2的幂倍数 (确保size是2的幂),且满足新容量 > ht[0].used * 2。

  • 缩容:
  • 负载因子 ≤ 0.1时,触发缩容。
    新容量为ht[0].used的最小2的幂倍数 (确保新容量 ≥ ht[0].used)。
2. 初始化ht1

为ht[1]分配新容量(即步骤1确定的大小),初始化其table数组。

3. 渐进式迁移元素

Redis不会一次性将ht[0]的所有元素迁移到ht[1],而是分多次、逐步迁移,避免单线程阻塞:

  • 维护一个rehashidx计数器(初始为0),标记当前迁移到ht[0].table的哪个索引位置。
  • 每次对字典执行增删改查操作 时,除了完成当前操作,还会顺带将ht[0].table[rehashidx]桶中的所有元素迁移到ht[1],然后rehashidx += 1。
  • 此外,Redis会在定时任务中批量迁移一部分元素(加速rehash过程)。
4. 迁移完成,切换哈希表

当ht[0]的所有元素都迁移到ht[1]后:

  • 释放ht[0]的内存。
  • 将ht[1]赋值给ht[0],重置ht[1]为空表。
  • 重置rehashidx = -1(标记rehash结束)。

四、rehash期间的操作处理

在rehash过程中(rehashidx != -1),字典的所有操作(增、删、改、查)需同时涉及ht[0]和ht[1],确保数据一致性:

  • 查询 :先查ht[0],若未找到再查ht[1]。
  • 插入 :直接插入到ht[1](避免ht[0]再次增长,加速迁移)。
  • 删除/修改 :若元素在ht[0]则操作ht[0],若在ht[1]则操作ht[1]。

五、核心优势:渐进式rehash

Redis的渐进式rehash避免了传统哈希表"一次性迁移"的性能问题:

  • 分散迁移压力:将迁移工作分摊到多次操作和定时任务中,每次迁移耗时极短(微秒级)。
  • 不阻塞服务:整个过程中,Redis仍能正常处理客户端请求,几乎无感知。

总结

Redis的rehash是通过渐进式迁移实现的哈希表容量调整机制:

  1. 基于负载因子触发,动态扩容或缩容。
  2. 使用两个哈希表(ht[0]和ht[1]),逐步迁移元素。
  3. 迁移期间正常处理请求,兼顾效率与可用性。

这种设计使Redis在面对大规模数据时,仍能维持高效的哈希表操作性能。

相关推荐
码途行者1 小时前
缓存一致性难题:Redis 和数据库如何做到数据一致?
数据库·redis
linweidong3 小时前
Redis 集群故障排查与修复实战:从 Connection refused 到内存打满的七个现场
运维·数据库·redis·缓存·redis集群·运维面经·实施面经
用户6222884048193 小时前
Redis 内存管理与过期淘汰策略:从 maxmemory 到 LRU / LFU,一篇讲透
java·redis
星夜离尘564 小时前
FIFO深度怎么定?用突发流量和背压算清缓存预算
缓存·fpga开发·verilog·fifo·背压
Sand(ContextGate)5 小时前
从零搭建电商智能导购 Agent:LangGraph 编排 + 三层记忆 + 熔断降级 + 生产部署全链路实战
redis·agent·fastapi·电商·chromadb·langgraph·智能导购
kyle~5 小时前
软件缓存一致性
缓存
bksczm5 小时前
Redis基础篇之初识分布式
数据库·redis·分布式
jyOverQ5 小时前
Redis 主从复制、Sentinel 和 Cluster 到底有什么区别?
java·redis·sentinel
仍然.13 小时前
Redis---缓存
数据库·redis·缓存
骇客野人15 小时前
微服务多级缓存架构设计
缓存·微服务·架构