
Redis 6.2&7 Rehash相关优化
一、Redis rehash问题回顾
Redis开发规范解析(三)--一个Redis最好存多少key 一文中详细介绍了Rehash的基本原理和可能产生的问题,这里不做详细介绍。
简单回顾下超出key阈值后,需要额外的hash表内存大小:
键值个数 | 需要额外的hash表内存大小 |
134,217,728 | 2GB |
67,108,864 | 1GB |
33,554,432 | 512.0MB |
16,777,216 | 256.0MB |
8,388,608 | 128.0MB |
4,194,304 | 64.0MB |
2,097,152 | 32.0MB |
1,048,576 | 16.0MB |
524,288 | 8.0MB |
随着key个数越多,rehash需要的额外内存也越大,所带来的可用性风险(大量逐出,Redis同步)和数据丢失(逐出)风险也越高。
二、Redis 6.2&7+ Rehash相关优化
Redis 6.2后对Rehash做了相关优化:
简单翻译:
三、实验
1. 版本选择
- Redis 6.0.15
- Redis 7.0.11
2. 实验条件
- maxmemory = 5.6GB
- 第一次灌入:67,100,000个key,观察内存
- 第二次灌入:2,000,000个key,观察可用性和逐出
3. 开始实验
(1) Redis 6.0.15
第一次灌入:67,100,000个key,观察内存:
第二次灌入:2,000,000个key,观察可用性和逐出
- 客户端执行超时, 超时近30秒以上,redis-cli --latency-history
- 逐出大量key:500万以上
- 峰值内存:rehash多了一个GB
(2) Redis 7.0.11
第一次灌入:67,100,000个key,观察内存:
第二次灌入:2,000,000个key,观察可用性和逐出
- 客户端执行无超时,redis-cli --latency-history
- 正常逐出 (还剩0.1GB)
- 峰值内存:没有进行rehash
4. 实验对比
版本 | 是否发生rehash | 严重超时 |
6.0.15 | 有 | 有,30秒以上不可用 |
7.0.11 | 无 | 无,正常逐出 |
四、代码解析
1. dict:
新加的expandAllowed,决定dict当前是否做rehash
dict在做扩容时候会加入新的判断dictTypeExpandAllowed
若dict的expandAllowed为空则允许rehash,否则执行expandAllowed
2. redis的dict
redis的dbDictType和dbExpiresDictType
可以看到:
- dict使用率大于hash负载因子:可以做rehash
- dict使用率小于hash负载因子:
- 如果maxmemory=0,可以做rehash
- 如果当前使用内存 + rehash需要内存小于maxmemory,可以做rehash
- 如果当前对象内存(使用内存 - 额外内存(各种缓冲区)) + rehash需要内存小于maxmemory,可以做rehash
五、结论
- Redis6.2+以上版本有效解决了rehash在大dict下产生的可用性和逐出问题
- Redis7目前已经比较稳定(2022年4月release),目前已经在线上大量使用7.0.11。
- 新版本只是做了rehash的延迟处理,并不是不再做rehash了,由于负载因子可能产生的性能问题需要适度关注。
- Redis6.2+对逐出也做了一定优化,后续将进行介绍:Incremental eviction processing
文章转载自公众号:Redis开发运维实战
