
Redis 6.2和7渐进式逐出优化
一、Redis 逐出功能简介
网上关于Redis逐出功能和算法的文章比较多,这里就不浪费篇幅介绍,本文旨在介绍Redis 6.2以后一个Redis逐出上的重大优化(渐进式逐出),顺带整理下Redis在各个版本上逐出功能上的优化。
Redis有一个maxmemory配置,每次执行命令时如果发现当前Redis使用内存超过maxmemory时,会使用相应的策略(包含不逐出也是一种策略)把key进行逐出,直到Redis使用内存小于maxmemory,这句话包含了几个重要信息,我们分别来看下。
1.每次执行命令时...直到Redis使用内存小于maxmemory
说明这个逐出检测是一个同步过程,如果逐出花费大量时间,Redis会长期不可用,甚至会触发切换。
2. 相应的策略
策略包含如下几种,可根据相应场景进行测试,默认是NO_EVICTION
3. Redis使用内存
这个使用内存可能会产生歧义,造成不符合预期的事件发生,使用内存定义
所以如果normal客户端缓冲区突增(例如持续执行很大的命令,例如lrange 大list),可能也会造成突发逐出。
4. 重要点总结
- 同步逐出: 如果逐出量很大(例如百万级别),可能严重影响可用性
- used_memory参考上图。
- “模拟的”LRU、LFU:可以看下代码,LFU和LRU不是真正的(真正的成本太高了),是用一个队列模拟的。
二、Redis 6.2&7+ 逐出实验
1. 版本选择
- Redis 6.0.15
- Redis 7.0.11
2. 实验条件
- maxmemory = 7.5 GB
- 第一次灌入:70,000,000个key(为了越过 67108864 界限),观察内存
- 第二次灌入:1,000,000个key,观察可用性和逐出 + 800MB string (40个20MB)
3. 开始实验
(1) 第一次灌入:7000w个key
可以看到两个版本内存消耗几乎一致,并且在整个导入过程中未发生异常
(2) 第二次灌入:1,000,000个key + 800MB string (40个20MB),观察可用性和逐出
客户端异常 | redis-cli latency | 耗时 | |
6.0.15 | 持续发生 | min: 29, max: 347 | 52500ms |
7.0.11 | 未发生 | min: 0, max: 25330 | 51233ms |
可以看到Redis 7.0.11在同等状况下,可用性表现良好,下面来看下相关原理
三、同步逐出与渐进式逐出(since 6.2+)
1. 同步逐出
文章开头已经提到:每次执行命令时如果发现当前使用内存超过maxmemory时,会使用相应的策略(包含不逐出也是一种策略)把key进行逐出,直到Redis使用内存小于maxmemory
2. 渐进式逐出
(1) evictionTimer运行时间超过eviction_time_limit_us后,会开启evict时间事件并退出逐出,这样将逐出循环异步化并保证可用性。
(2) eviction_time_limit_us计算方法:
可以看到新增maxmemory_eviction_tenacity参数用来控制超时:
- 当maxmemory_eviction_tenacity<=10,超时时间等50微秒 * maxmemory_eviction_tenacity
- 当maxmemory_eviction_tenacity>10 and maxmemory_eviction_tenacity<100,超时时间等于500 * 1.15^(maxmemory_eviction_tenacity - 10.0),该值最大为2分钟
- 当maxmemory_eviction_tenacity = 100,代表没有超时时间,和同步逐出一致。
(3) 用isEvictionProcRunning控制逐出时间事件
3. 风险讨论?
可以看到不同的maxmemory_eviction_tenacity值,逐出的粒度不尽相同:
- 过低:可用性可以保证,但内存可能会持续增加(生产大于逐出),需要通过监控观测。
- 过高:可用性可能有问题,但内存可以得到控制。
四、历届版本的重要优化
下图展示了Redis在各个版本evict的相关优化和功能(如有漏掉,欢迎指正)
1. Redis 3->Redis 4
- Redis 4引入了LRU算法:详见http://antirez.com/news/109
- Volatile-ttl和LFU、LRU一样使用了evict pool(一个采样的LFU、LFU、TTL池子进行排列)来实现。
- 逐出支持异步删除:lazyfree-lazy-eviction
2. Redis 4->Redis 5
- aof加载期间不执行evict逻辑
- keys命令不触发evict逻辑
3. Redis 5->Redis 6
- 记录lazyfree evcit的latency
- evict支持tracking
4. Redis 6->Redis 6.2、7.0
- 同步逐出改为渐进式逐出 (6.2)
- 添加新的info:total_eviction_exceeded_time and current_eviction_exceeded_time (7.0)
五、结论
- Redis 7可以放心使用,内存、性能、可用性都有一定提升。
- maxmemory_eviction_tenacity默认是10,可以动态设置,maxmemory_eviction_tenacity=100的话可能存在bug(感谢仲肥大佬(Zhao Zhao)提示)
- Redis 6.2需要大于6.2.8
- Redis 7.0需要大于7.0.5
文章转载自公众号:Redis开发运维实战
