走进Redis的渐进式Rehash
        【摘要】 Redis 的渐进式 Rehash 是一种避免一次性大规模数据迁移导致服务阻塞的优化机制,主要用于哈希表(Hash Table)的扩容(rehash)和缩容操作。它的核心思想是将耗时的 rehash 过程分散到多次请求中逐步完成,从而保证 Redis 服务的响应性。一、为什么需要渐进式 Rehash?背景问题Redis 的哈希表(如字典 dict)是核心数据结构,当元素数量增...
    
    
    
    Redis 的渐进式 Rehash 是一种避免一次性大规模数据迁移导致服务阻塞的优化机制,主要用于哈希表(Hash Table)的扩容(rehash)和缩容操作。它的核心思想是将耗时的 rehash 过程分散到多次请求中逐步完成,从而保证 Redis 服务的响应性。
一、为什么需要渐进式 Rehash?
- 
背景问题 
 Redis 的哈希表(如字典dict)是核心数据结构,当元素数量增加时,需要扩容(rehash)以减少哈希冲突;当元素减少时,需要缩容以节省内存。
 一次性 Rehash 的问题:如果哈希表非常大(例如百万级键值),一次性迁移所有键值会阻塞主线程,导致 Redis 服务暂停响应。
- 
渐进式 Rehash 的优势 - 非阻塞:将 Rehash 分散到多次操作中,每次只迁移少量数据,避免长时间阻塞。
- 平滑过渡:在 Rehash 期间,Redis 仍能正常处理读写请求,保证高可用性。
 
二、Rehash 触发条件
Redis 的哈希表(dict)会在以下情况触发 Rehash:
- 扩容:当哈希表的负载因子(元素数量 / 哈希桶数量)超过 1(默认阈值)时,触发扩容(通常是翻倍)。
- 缩容:当负载因子低于 0.1时,触发缩容(通常是减半)。
三、渐进式 Rehash 的过程
1. 初始化阶段
- 当需要 Rehash 时,Redis 会创建一个新的哈希表(ht[1]),大小为原哈希表(ht[0])的两倍(扩容)或一半(缩容)。
- 设置 rehashidx = 0,表示从ht[0]的第一个桶开始迁移。
2. 渐进式迁移
- 每次操作附带迁移:在 Redis 执行命令(如 GET、SET、HGET等)时,会顺带迁移ht[0]中的一部分数据到ht[1]。
- 迁移步骤:
 每次迁移一个哈希桶(bucket)中的所有键值对。例如,首次迁移ht[0]的第0号桶,第二次迁移第1号桶,依此类推。
- 更新 rehashidx:每迁移完一个桶,rehashidx递增,直到所有桶迁移完成(rehashidx == ht[0].size)。
3. 完成 Rehash
- 当所有桶迁移完成后,Redis 将 ht[1]设为新的主哈希表(ht[0] = ht[1]),并释放旧的ht[0]。
- 此时,Rehash 结束。
四、Rehash 期间的数据访问
在渐进式 Rehash 过程中,Redis 需要同时处理旧表(ht[0])和新表(ht[1])的读写操作:
- 查找操作:
- 先在 ht[0]的当前rehashidx范围内查找,如果未找到,则到ht[1]中查找。
 // 伪代码示例 def get(key): if rehashing: idx = dict_rehashidx(d) bucket = &d->ht[0].table[idx] while (bucket->used > 0) { if (key matches) return value; bucket++; } // 如果旧表未找到,转向新表 return lookup_in_ht1(key); else: return lookup_in_ht0(key);
- 先在 
- 写入操作:
- 直接写入 ht[1],保证新数据不会丢失。
 
- 直接写入 
- 删除操作:
- 需同时在 ht[0]和ht[1]中删除(如果存在)。
 
- 需同时在 
五、关键细节
- 
Rehash 索引 ( rehashidx)- 记录当前迁移进度,初始为 0,完成时为ht[0].size。
- 可通过 INFO keyspace命令查看rehashidx的值(例如dict_rehashidx:0表示正在 Rehash)。
 
- 记录当前迁移进度,初始为 
- 
强制触发 Rehash 
 可以通过SHUTDOWN SAVE或CONFIG SET active-defrag yes强制触发 Rehash,但需谨慎使用。
- 
性能影响 - 渐进式 Rehash 会略微增加每个请求的处理时间(因为需要同时处理迁移),但避免了阻塞。
- 在极端情况下(如海量数据),Rehash 可能持续较长时间,但整体影响可控。
 
六、示例流程
假设 ht[0] 有 4 个桶,需要扩容到 8 个桶:
- 初始化 ht[1](8 个桶),设置rehashidx = 0。
- 处理第一个请求时,迁移 ht[0]的第0号桶。
- 处理第二个请求时,迁移 ht[0]的第1号桶。
- 重复上述步骤,直到 rehashidx = 4,表示迁移完成。
- 释放 ht[0],ht[1]成为主表。
七、总结
- 渐进式 Rehash 是 Redis 为避免大规模数据迁移导致阻塞而设计的优化机制。
- 核心过程:分批次迁移哈希桶,每次操作附带迁移一部分数据。
- 优点:保证服务不中断,适用于高并发场景。
- 代价:迁移期间每个操作略微变慢,但整体性能影响可接受。
通过这种设计,Redis 在保证高性能的同时,能够安全地处理哈希表的动态扩缩容。
            【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
                cloudbbs@huaweicloud.com
                
            
        
        
        
        
        
        
        - 点赞
- 收藏
- 关注作者
 
             
           
评论(0)