Redis原理篇——内存回收
创始人
2024-03-18 11:55:02
0

Redis是基于内存存储的,性能强。Redis的性能瓶颈也在于内存,但是单节点内存不宜过大,会影响持久化或主从同步性能。

通过配置文件来设置Redis的最大内存:
在这里插入图片描述

一、过期策略

Redis是键值类型的数据库,所有的key和value保存在 Dict 结构中,在Redis数据库结构体中,有两个Dict:一个用来记录key-value,另一个记录key-TTL

typedef struct redisDb {dict *dict;                 /* 存放所有key和value */dict *expires;              /* 存放key和对应的TTL存活时间 只包含设置了TTL的key */dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/dict *ready_keys;           /* Blocked keys that received a PUSH */dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS (事务) */int id;                     /* Database ID 使用的是几号库 0~15 */long long avg_ttl;          /* Average TTL, 平均TTL时间 */unsigned long expires_cursor; /* expire检查时在dict中抽取的索引位置 */list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;

在这里插入图片描述
因此只需要查Redis中的key对应的TTL,就可以判断这个key是否过期

删除策略

TTL到期就立刻删除吗?

可以设置定时器,当一个key到期了就立刻删除,但是对于大量key来说,设置大量定时器对CPU的占用率高,影响Redis主线程的性能,因此Redis不会立刻删除到期的key

1.惰性删除:

在访问一个key的时候检查该key的存活时间,如果已经过期了才执行删除。

robj *lookupKeyWriteWithFlags(redisDb *db, robj *key, int flags) {// 检查key是否过期expireIfNeeded(db,key);return lookupKey(db,key,flags);
}robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {robj *val;// 检查key是否过期if (expireIfNeeded(db,key) == 1) {/*......... 略*/ }/*......... 略*/
}int expireIfNeeded(redisDb *db, robj *key) {// 判断是否过期,如果没过期就返回0if (!keyIsExpired(db,key)) return 0;/*......... 略*//* 删除过期的key */deleteExpiredKeyAndPropagate(db,key);return 1;
}

惰性删除存在的问题:

惰性删除是在访问一个key的时候检查是否过期,如果一个key过期了但是客户端长时间没有操作,那么这个key就一直不能被删除,如果这样的key存在大量的,那么就会一直占据着内存,影响性能。

2.周期删除

周期性的抽样一部分过期的key,然后执行删除。
执行周期有两种:

  • SLOW模式: Redis会设置一个定时任务serverCron(),按照server.hz的频率来执行过期key清理
  1. 执行频率受server.hz影响,默认为10,即每秒执行10次,每个执行周期100ms
  2. 执行清理耗时不超过一次执行周期的25%
  3. 逐个遍历db,抽取20个key判断是否过期
  4. 如果没达到时间上限(25ms)并且过期key比例大于10%,再进行一次抽样,否则结束
  • FAST模式: Redis的每个事件循环前会调用beforeSleep()函数,执行过期key清理
  1. 执行频率受beforeSleep()调用频率影响,但两次FAST模式间隔不低于2ms
  2. 执行清理耗时不超过1ms
  3. 依次遍历db,抽取20个key判断是否过期
  4. 如果没达到时间上限(1ms)并且过期key比例大于10%,再进行一次抽样,否则结束

二、内存淘汰策略

内存淘汰: Redis内存使用达到设置的阈值时,Redis主动挑选部分key删除以释放内存。

Redis支持8种不同的策略:

  • noeviction: 不淘汰任何key,内存满时不允许写入新数据(默认策略)
  • volatile-ttl:对设置TTL的key,比较剩余的TTL值,先淘汰数值小的
  • allkeys-random: 对全体key,随机进行淘汰。
  • volatile-random:对设置了TTL的key,随机淘汰。
  • allkeys-lru:对全体key,基于LRU算法进行淘汰
  • volatile-lru:对设置了TTL的key,基于LRU算法进行淘汰
  • allkeys-lfu:对全体key,基于LFU算法进行淘汰
  • volatile-lfu:对设置了TTL的key,基于LFU算法进行淘汰
typedef struct redisObject {unsigned type:4; // 对象类型,分别为五种基本数据类型  占4个bit位unsigned encoding:4; // 编码方式 11 中 占4个bit位unsigned lru:LRU_BITS; /*LRU以秒为单位记录最近一次访问时间,长度为24bit  LFU:高16位以分钟为单位记录最近一次访问时间,低8位记录逻辑访问次数*/int refcount;  // 引用计数器 0表示对象无人引用 可以被回收void *ptr;  // 指针,指向存放实际数据的空间
} robj;

LFU的访问次数之所以叫逻辑访问次数,是因为并不是每次key被访问都计数。而是通过运算:

  1. 生成0~1之间的随机数R
  2. 计算1/(旧次数*lfu_log_factor+1),记录为P,lfu_log_factor默认为10
  3. 如果R,计数器+1,最大不超过255
  4. 访问次数会随时间衰减,距离上一次访问时间每隔lfu_decay_time分钟(默认1),计数器-1

相关内容

热门资讯

汽车油箱结构是什么(汽车油箱结... 本篇文章极速百科给大家谈谈汽车油箱结构是什么,以及汽车油箱结构原理图解对应的知识点,希望对各位有所帮...
重大消息战皇大厅开挂是真的吗... 您好:战皇大厅这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
嵌入式 ADC使用手册完整版 ... 嵌入式 ADC使用手册完整版 (188977万字)💜&#...
盘点十款牵手跑胡子为什么一直... 您好:牵手跑胡子这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游...
senator香烟多少一盒(s... 今天给各位分享senator香烟多少一盒的知识,其中也会对sevebstars香烟进行解释,如果能碰...
终于懂了新荣耀斗牛真的有挂吗... 您好:新荣耀斗牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信8435338】很多玩家在这款游戏...
盘点十款明星麻将到底有没有挂... 您好:明星麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
总结文章“新道游棋牌有透视挂吗... 您好:新道游棋牌这款游戏可以开挂,确实是有挂的,需要了解加客服微信【7682267】很多玩家在这款游...
终于懂了手机麻将到底有没有挂... 您好:手机麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
终于懂了贵明月游戏怎么装挂-... 您好,贵明月游戏这款游戏可以开挂的,确实是有挂的,需要了解加微【8435338】很多玩家在这款游戏中...