加入收藏 | 设为首页 | 会员中心 | 我要投稿 淮北站长网 (https://www.0561zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 交互 > 正文

redis lru实现策略

发布时间:2016-11-01 18:21:21 所属栏目:交互 来源:站长网
导读:副标题#e# 在使用redis作为缓存的场景下,内存淘汰策略决定的redis的内存使用效率。在大部分场景下,我们会采用LRU(Least Recently Used)来作为redis的淘汰策略。本文将由浅入深的介绍redislru策略的具体实现。 首先我们来科普下,什么是LRU ?(以下来自维

点击(此处)折叠或打开

  1. void databasesCron(void){
  2.    /* Expire keys by random sampling. Not required for slaves
  3.     * as master will synthesize DELs for us. */
  4.     if (server.active_expire_enabled && server.masterhost == NULL)
  5.         activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
  6.     …..
  7. }
主动淘汰是通过activeExpireCycle 来实现的,这部分的逻辑如下:
   1.遍历至多16个DB 。【由宏CRON_DBS_PER_CALL定义,默认为16】    2.随机挑选20个带过期时间的key。【由宏ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP定义,默认20】    3.如果key过期,则将key相关的内存释放,或者放入失效队列。    4.如果操作时间超过允许的限定时间,至多25ms。(timelimit =    1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100,       ,ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC=25,server.hz默认为10), 则此次淘汰操作结束返回,否则进入5。    5.如果该DB下,有超过5个key (ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4=5) 实际失效,则进入 2,否则选择下一个DB,再次进入2。    6.遍历完成,结束。
 流程图如下
注:(图中大于等于%5的可以是实际过期的,应改为大于等于%25的key是实际过期的。iteration++是在遍历20个key的时候,每次加1)。
redis lru实现策略        被动淘汰 - 内存不够,调用activeExpireCycle释放  该步骤的实现方式如下:

点击(此处)折叠或打开

  1. processCommand 函数关于内存淘汰策略的逻辑:
  2. /* Handle the maxmemory directive.
  3. *
  4. * First we try to free some memory if possible (if there are volatile
  5. * keys in the dataset). If there are not the only thing we can do
  6. * is returning an error. */
  7. if (server.maxmemory) {
  8. int retval = freeMemoryIfNeeded();
  9. /* freeMemoryIfNeeded may flush slave output buffers. This may result
  10. * into a slave, that may be the active client, to be freed. */
  11. if (server.current_client == NULL) return C_ERR;

  12. /* It was impossible to free enough memory, and the command the client
  13. * is trying to execute is denied during OOM conditions? Error. */
  14. if ((c->cmd->flags & CMD_DENYOOM) && retval == C_ERR) {
  15. flagTransaction(c);
  16. addReply(c, shared.oomerr);
  17. return C_OK;
  18. }
  19. }
每次执行命令前,都会调用freeMemoryIfNeeded来检查内存的情况,并释放相应的内存,如果释放后,内存仍然不够,直接向请求的客户端返回OOM。 具体的步骤如下:
   1.获取redis server当前已经使用的内存mem_reported。    2.如果mem_reported < server.maxmemory ,则返回ok。否则mem_used=mem_reported,进入步骤3。    3.遍历该redis的所slaves,mem_used减去所有slave占用的ClientOutputBuffer。    4.如果配置了AOF,mem_used减去AOF占用的空间。sdslen(server.aof_buf)+aofRewriteBufferSize()。    5.如果mem_used < server.maxmemory,返回ok。否则进入步骤6。    6.如果内存策略配置为noeviction,返回错误。否则进入7。     7.如果是LRU策略,如果是VOLATILE的LRU,则每次从可失效的数据集中,每次随机采样maxmemory_samples(默认为5)个key,从中选取idletime最大的key进行淘汰。       否则,如果是ALLKEYS_LRU则从全局数据中进行采样,每次随机采样maxmemory_samples(默认为5)个key,并从中选择idletime最大的key进行淘汰。    8.如果释放内存之后,还是超过了server.maxmemory,则继续淘汰,只到释放后剩下的内存小于server.maxmemory为止。
被动淘汰 每次访问相关的key,如果发现key过期,直接释放掉该key相关的内存: 每次访问key,都会调用expireIfNeeded来判断key是否过期,如果过期,则释放掉,并返回null,否则返回key的值。

总结  1.redis做为缓存,经常采用LRU的策略来淘汰数据,所以如果同时过期的数据太多,就会导致redis发起主动检测时耗费的时间过长(最大为250ms),从而导致最大应用超时 >= 250ms。

(编辑:淮北站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读