内存策略

内存回收

1、当内存使用达到上限时,就无法存储更多数据

2、Redis 提供策略实现内存回收

(1)内存过期策略

(2)内存淘汰策略

 

过期策略

1、通过 expire 命令给 Redis 的 key 设置 TTL(存活时间)

2、Redis 判断一个 key 过期

(1)Redis 本身是一个 key-value 内存存储数据库,所有 key、value 都保存在 Dict 结构中

(2)在其 database 结构体中,有两个 Dict:一个记录 key-value,另一个记录 key-TTL

typedef struct redisDb {
    dict *dict;                 /* 存放所有key及value的地方,也被称为keyspace*/
    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;          /* 记录平均TTL时长 */
    unsigned long expires_cursor; /* expire检查时在dict中抽样的索引位置. */
    list *defrag_later;         /* 等待碎片整理的key列表. */
} redisDb;

3、惰性删除:在访问一个 key 时,检查该 key 存活时间,如果已经过期才执行删除

4、周期删除

(1)通过一个定时任务,周期性的抽样部分过期的 key,然后执行删除,执行周期有两种

(2)Redis 服务初始化函数 initServer() 中设置定时任务,按照 server.hz 频率来执行过期 key 清理,模式为 SLOW

(3)Redis 每个事件循环前会调用 beforeSleep() 函数,执行过期 key 清理,模式为 FAST

5、SLOW 模式规则

(1)执行频率受 server.hz 影响,默认为 10,即每秒执行 10 次,每个执行周期 100ms

(2)执行清理耗时不超过一次执行周期的 25%,默认 slow 模式耗时不超过 25ms

(3)逐个遍历 db,逐个遍历 db 中的 bucket,抽取 20 个 key 判断是否过期

(4)如果没达到时间上限(25ms)并且过期 key 比例大于10%,再进行一次抽样,否则结束

6、FAST 模式规则(过期 key 比例小于 10% 不执行)

(1)执行频率受 beforeSleep() 调用频率影响,但两次 FAST 模式间隔不低于 2ms

(2)执行清理耗时不超过 1ms

(3)逐个遍历 db,逐个遍历 db 中的 bucket,抽取 20 个 key 判断是否过期

(4)如果没达到时间上限(1ms)并且过期 key 比例大于 10%,再进行一次抽样,否则结束

 

淘汰策略

1、当 Redis 内存使用达到设置的上限时,主动挑选部分 key 删除,以释放更多内存的流程

2、Redis 会在处理客户端命令的方法 processCommand() 中尝试做内存淘汰

3、Redis 支持 8 种不同策略,选择所删除的 key

(1)noeviction:不淘汰任何 key,但是内存满时不允许写入新数据,默认此策略

(2)volatile-ttl:对设置 TTL 的 key,比较 key 的剩余 TTL 值,TTL 越小越先被淘汰

(3)allkeys-random:对全体 key ,随机进行淘汰,直接从 db -> dict 中随机挑选

(4)volatile-random:对设置 TTL 的 key ,随机进行淘汰,从 db->expires 中随机挑选

(5)allkeys-lru:对全体 key,基于 LRU 算法进行淘汰

(6)volatile-lru:对设置 TTL 的 key,基于 LRU 算法进行淘汰

(7)allkeys-lfu:对全体 key,基于 LFU 算法进行淘汰

(8)volatile-lfu:对设置 TTL 的 key,基于 LFU 算法进行淘汰

4、算法

(1)LRU(Least Recently Used):最少最近使用,当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高

(2)LFU(Least Frequently Used):最少频率使用,统计每个 key 访问频率,值越小淘汰优先级越高

5、Redis 数据都会被封装为 RedisObject 结构

typedef struct redisObject {
    unsigned type:4;        // 对象类型
    unsigned encoding:4;    // 编码方式
    unsigned lru:LRU_BITS;  // LRU:以秒为单位记录最近一次访问时间,长度24bit
    // LFU:高16位以分钟为单位记录最近一次访问时间,低8位记录逻辑访问次数
    int refcount;           // 引用计数,计数为0则可以回收
    void *ptr;              // 数据指针,指向真实数据
} robj;

6、LFU 逻辑访问次数,不是每次 key 被访问都计数,而是通过运算

(1)生成 0~1 之间的随机数 R

(2)计算:旧次数 * lfu_log_factor + 1,记录为 P

(3)如果 R < P ,则计数器 + 1,且最大不超过 255

(4)访问次数会随时间衰减,距离上一次访问时间每隔 lfu_decay_time 分钟,计数器 - 1

posted @   半条咸鱼  阅读(33)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示