当前位置: 首页 > news >正文

Redis原理 - 内存策略

原文首更地址,阅读效果更佳!

Redis原理 - 内存策略 | CoderMast编程桅杆icon-default.png?t=N5K3https://www.codermast.com/database/redis/redis-memery-strategy.html

Redis 本身是一个典型的 key-value 内存存储数据库,因此所有的 key、value 都保存在之前学习过的 Dict 结构中。不过在其 database 结构体中,有两个 Dict :一个用来记录 key-value;另外一个用来记录 key-TTL

typedef struct redisDb {dict *dict;     // 存放所有 key 和 value 的地方dict *expires;  // 存放每一个 key 及其对应的 TTL 存活时间,只包含设置了 TTL 的 keydict *blocking_keys;   dict *ready_keys;dict *watched_keys;int id;         // Database ID :0 ~ 15long long avg_ttl;  unsigned long expires_cursor;   // expire 检查时在 dict 中抽样的索引位置list *defrag_later; // 等待碎片整理的 key 列表
} redisDb;

Redis 是如何知道一个 key 是否过期呢?

答:利用两个 Dict 分别记录 key-value 和 key-ttl

是不是 TTL 到期就立刻删除呢?

答:并不是到期立刻删除,而是采用 惰性删除 和 周期删除

#删除策略

  • 定时删除:TTL 到期后,立刻删除对应的 key

  • 惰性删除:并不是在 TTL 到期后就立刻删除,而是在访问一个 key 的时候,检查该 key 的存活时间,如果已经过期,才执行删除。

  • 周期删除:是通过一个定时任务,周期性的抽样部分过期的 key,然后执行删除。执行周期有两种:

    • Redis 会设置一个定时任务 serverCron(),按照 server.hz 的频率来执行过期 key 清理,模式为 SLOW,默认为 10
    • Redis 的每个事情循环前会调用beforeSleep()函数,执行过期key清理,模式为FAST

SLOW模式规则:

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

  2. 执行清理耗时不超过一次执行周期的25%.

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

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

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

  1. 执行频率受beforeSleep()调用频率影响,但两次FAST模式间隔不低于2ms
  2. 执行清理耗时不超过1ms
  3. 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期
  4. 如果没达到时间上限 (1ms)并且过期key比例大于10%,再进行一次抽样,否则结束

#淘汰策略

内存淘汰就是当 Redis 内存使用达到设置的阈值时,Redis 主动挑选部分 key 删除以释放更多的内存的流程。Redis 会在处理客户端命令的方法 processCommand() 中尝试做内存淘汰。

Redis 一共支持 8 种淘汰策略

  • noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键。

  • allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键。

  • volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键。

  • allkeys-random:加入键的时候如果过限,从所有key随机删除。

  • volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐。

  • volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键。

  • volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键。

  • allkeys-lfu:从所有键中驱逐使用频率最少的键。

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

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

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

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

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

http://www.lryc.cn/news/94196.html

相关文章:

  • 【计算机网络】IP 地址处理函数
  • 9i物联网浏览器(cef_114.2.110114.2.100支持H264视频)WinForm-CefSharp114(5735)视频版本体验
  • 如何在本地运行一个已关服但具有客户端的游戏
  • C语言编程—预处理器
  • 使用 Maya Mari 设计 3D 波斯风格道具(p1)
  • Redis分布式问题
  • synchronized原理
  • 10G光模块能兼容千兆光口吗
  • css 显示省略号 和 动态显示省略号
  • LeetCode 1253. 重构 2 行二进制矩阵
  • 【八股】【C++】内存
  • 数据库G等待
  • PCB封装设计指导(一)基础知识
  • Flask框架之Restful--介绍--下载--基本使用
  • 2023年上海市浦东新区网络安全管理员决赛理论题样题
  • SQL语言的四大组成部分——DCL(数据控制语言)
  • ChatGPT新功能曝光:可记住用户信息、上传文件和工作区
  • 【Unity编辑器扩展】(三)PSD转UGUI Prefab, 一键拼UI解放美术/程序(完结)
  • SpringBoot开发Restful风格的接口实现CRUD功能
  • 【Servlet学习三】实现一个内存版本的简易计算器~
  • Linux c语言获取本机网关 ip 地址
  • nginx部署本地项目如何让异地公网访问?服务器端口映射配置!
  • 云时代已至,新一代数据分析平台是如何实现的?
  • 【C#】简单聊下Framework框架下的事务
  • asyncPool并发执行请求函数
  • Ubuntu 22.04上安装NFS服务
  • 数据结构--双链表
  • javassist 动态修改 jar 包中 class
  • 什么是CC攻击?
  • ​LeetCode解法汇总253. 重构 2 行二进制矩阵