首页 > 行业资讯 > Redis 6.2 和 7 渐进式逐出优化

Redis 6.2 和 7 渐进式逐出优化

时间:2023-11-24 来源: 浏览:

Redis 6.2 和 7 渐进式逐出优化

付磊 twt企业IT社区
twt企业IT社区

talkwithtrend

talkwithtrend.com社区(即twt社区)官方公众号,持续发布优秀社区原创内容。内容深度服务企业内各方向的架构师、运维主管、开发和运维工程师等IT专业岗位人群,让您时刻和国内企业IT同行保持信息同步。

收录于合集
【导读】 本文将介绍Redis 6.2以后一个Redis逐出上的重大优化(渐进式逐出),顺带整理下Redis在各个版本上逐出功能上的优化。

【作者】付磊, 从业十余年,历任搜狐视频高级开发工程师、阿里云Redis技术专家、快手cache(redis memcahce elasticsearch等)负责人等,有线上80万Redis实例运维经验。出版有《Redis开发与运维》一书,开源作品:“cachecloud:redis私有云平台”。

一、Redis 逐出功能简介

网上关于Redis逐出功能和算法的文章比较多,这里就不浪费篇幅介绍,本文旨在介绍Redis 6.2以后一个Redis逐出上的重大优化(渐进式逐出),顺带整理下Redis在各个版本上逐出功能上的优化。

Redis有一个maxmemory配置,每次执行命令时如果发现当前Redis使用内存超过maxmemory时,会使用相应的策略(包含不逐出也是一种策略)把key进行逐出,直到Redis使用内存小于maxmemory,这句话包含了几个重要信息,我们分别来看下。

1.每次执行命令时...直到Redis使用内存小于maxmemory

说明这个逐出检测是一个同步过程,如果逐出花费大量时间,Redis会长期不可用,甚至会触发切换。

2. 相应的策略

策略包含如下几种,可根据相应场景进行测试,默认是NO_EVICTION

MAXMEMORY_VOLATILE_LRU MAXMEMORY_VOLATILE_LFU MAXMEMORY_VOLATILE_TTL MAXMEMORY_VOLATILE_RANDOM MAXMEMORY_ALLKEYS_LRU MAXMEMORY_ALLKEYS_LFU MAXMEMORY_ALLKEYS_RANDOM MAXMEMORY_NO_EVICTION

3. Redis使用内存

这个使用内存可能会产生歧义,造成不符合预期的事件发生,使用内存定义

使用内存 = used_memory - AOF缓冲区 - slave缓冲区

所以如果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)

./redis-cli debug populate 40 user 20971520

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时间事件并退出逐出,这样将逐出循环异步化并保证可用性。

        //开始计时         elapsedStart(&evictionTimer);         /* Finally remove the selected key. */          if  (bestkey) {             db = server.db+bestdbid;             robj *keyobj = createStringObject(bestkey,sdslen(bestkey));             delta = (long long) zmalloc_used_memory();             latencyStartMonitor(eviction_latency);              if  (server.lazyfree_lazy_eviction)                 dbAsyncDelete(db,keyobj);              else                 dbSyncDelete(db,keyobj);             delta -= (long long) zmalloc_used_memory();             mem_freed += delta;             keys_freed++;              if  (keys_freed % 16 == 0) {                  if  (slaves) flushSlavesOutputBuffers();                  if  (server.lazyfree_lazy_eviction) {                      if  (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) {                          break ;                     }                 }                 /* After some time,  exit  the loop early - even  if  memory  limit                  * hasn ’t been reached.  If we suddenly need to free a lot of                  * memory, don’ t want to spend too much time here.  */                  if  (elapsedUs(evictionTimer) > eviction_time_limit_us) {                     // We still need to free memory - start eviction timer proc                     startEvictionTimeProc();                      break ;                 }             }         }

(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,代表没有超时时间,和同步逐出一致。

static unsigned long  evictionTimeLimitUs () {     serverAssert(server.maxmemory_eviction_tenacity >= 0);     serverAssert(server.maxmemory_eviction_tenacity <= 100);      if  (server.maxmemory_eviction_tenacity <= 10) {         /* A linear progression from 0..500us */          return  50uL * server.maxmemory_eviction_tenacity;     }      if  (server.maxmemory_eviction_tenacity < 100) {         /* A 15% geometric progression, resulting  in  a  limit  of ~2 min at tenacity==99  */          return  (unsigned long)(500.0 * pow(1.15, server.maxmemory_eviction_tenacity - 10.0));     }      return  ULONG_MAX;   /* No  limit  to eviction time */ }

(3) 用isEvictionProcRunning控制逐出时间事件

static int isEvictionProcRunning = 0; static int evictionTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData) {      if  (performEvictions() == EVICT_RUNNING)  return  0;  /* keep evicting */     /* For EVICT_OK - things are good, no need to keep evicting.      * For EVICT_FAIL - there is nothing left to evict.  */     isEvictionProcRunning = 0;      return  AE_NOMORE; } void startEvictionTimeProc(void) {      if  (!isEvictionProcRunning) {         isEvictionProcRunning = 1;         aeCreateTimeEvent(server.el, 0, evictionTimeProc, NULL, NULL);     } }

3. 风险讨论?

* A new incremental eviction mechanism that reduces latency on eviction spikes ( #7653)   In pathological cases this can cause memory to grow uncontrolled and may require   specific tuning.

可以看到不同的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)

五、结论

  1. Redis 7可以放心使用,内存、性能、可用性都有一定提升。
  2. maxmemory_eviction_tenacity默认是10,可以动态设置,maxmemory_eviction_tenacity=100的话可能存在bug(感谢仲肥大佬(Zhao Zhao)提示)
  • Redis 6.2需要大于6.2.8
  • Redis 7.0需要大于7.0.5

* Fix a hang when eviction is combined with lazy-free and maxmemory-eviction-tenacity   is  set  to 100 ( #11237)

有问题可点击 阅读原文 ,到社区原文下留言或评论

觉得本文有用,请 转发 或点击 “赏” ,让更多同行看到

 资料/文章推荐:

  • Redis 安装部署(一主二从三哨兵)

  • Redis 在 Linux 系统的配置优化

  • Redis 复制机制详解

  • Redis Cluster Operator容器化方案

欢迎关注社区  “Redis”技术主题  ,将会不断更新优质资料、文章。地址: https://www.talkwithtrend.com/Topic/91

下载 twt 社区客户端 APP

长按识别二维码即可下载

或到应用商店搜索“twt”

长按二维码关注公众号

*本公众号所发布内容仅代表作者观点,不代表社区立场

版权:如无特殊注明,文章转载自网络,侵权请联系cnmhg168#163.com删除!文件均为网友上传,仅供研究和学习使用,务必24小时内删除。
相关推荐