Redis的内存淘汰算法

news/2024/11/8 20:25:14/

 博客主页:🏆看看是李XX还是李歘歘 🏆

🌺每天不定期分享一些包括但不限于计算机基础、算法、后端开发相关的知识点,以及职场小菜鸡的生活。🌺

💗点关注不迷路,总有一些📖知识点📖是你想要的💗

⛽️今天的内容是     Redis的内存淘汰算法     ⛽️💻💻💻

首先来讨论一下Redis的过期键的删除策略有哪些?

定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。

惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

定期删除:每隔一定的时间,会扫描redis数据库的expires(过期)字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。

Redis的内存满了怎么办?

实际上Redis定义了「8种内存淘汰策略」用来处理redis内存满的情况:

在Redis中是可以设置内存最大限制的,因此我们不用担心Redis占满机器的内存影响其他服务,这个参数maxmemory是可以配置的,maxmemory参数默认值为0。因32位系统支持的最大内存为4GB,所以在32位系统上Redis的默认最大内存限制为3GB;在64位系统上默认Redis最大内存即为物理机的可用内存;

Redis的maxmemory支持的内存淘汰机制使得其成为一种有效的缓存方案,成为memcached(一套分布式的高速缓存系统)的有效替代方案。

当内存达到maxmemory后,Redis会按照maxmemory-policy启动淘汰策略。

Redis 3.0中已有淘汰机制:

maxmemory-policy含义特性
noeviction不淘汰内存超限后写命令会返回错误(如OOM, del命令除外)
allkeys-lru所有key的LRU机制在所有key中按照最近最少使用LRU原则剔除key,释放空间
volatile-lru易失key的LRU仅以设置过期时间key范围内的LRU(如均未设置过期时间,则不会淘汰)
allkeys-random所有key随机淘汰一视同仁,随机
volatile-random易失Key的随机仅设置过期时间key范围内的随机
volatile-ttl易失key的TTL淘汰优先删除剩余时间(time to live,TTL)短的key

其中LRU(less recently used)经典淘汰算法在Redis实现中有一定优化设计,来保证内存占用与实际效果的平衡,这也体现了工程应用是空间与时间的平衡性。

PS:值得注意的,在主从复制模式Replication下,从节点达到maxmemory时不会有任何异常日志信息,但现象为增量数据无法同步至从节点。

Redis 3.0中近似LRU算法

Redis中LRU是近似LRU实现,并不能取出理想LRU理论中最佳淘汰Key,而是通过从小部分采样后的样本中淘汰局部LRU键。

Redis 3.0中近似LRU算法通过增加待淘汰元素池的方式进一步优化,最终实现与精确LRU非常接近的表现。

精确LRU会占用较大内存记录历史状态,而近似LRU则用较小内存实现近似效果。

以下是理论LRU和近似LRU的效果对比:

总结图中展示规律,

结论:

数据访问模式非常接近幂次分布时,也就是大部分的访问集中于部分键时,LRU近似算法会处理得很好。

在模拟实验的过程中,我们发现如果使用幂次分布的访问模式,真实LRU算法和近似LRU算法几乎没有差别。

采样值设置通过maxmemory-samples指定,可通过CONFIG SET maxmemory-samples <count>动态设置,也可启动配置中指定maxmemory-samples <count>

源码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
int freeMemoryIfNeeded(void){while (mem_freed < mem_tofree) {if (server.maxmemory_policy == REDIS_MAXMEMORY_NO_EVICTION)return REDIS_ERR; /* We need to free memory, but policy forbids. */if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM){......}/* volatile-random and allkeys-random policy */if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM ||server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_RANDOM){......}/* volatile-lru and allkeys-lru policy */else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU){// 淘汰池函数evictionPoolPopulate(dict, db->dict, db->eviction_pool);while(bestkey == NULL) {evictionPoolPopulate(dict, db->dict, db->eviction_pool);// 从后向前逐一淘汰for (k = REDIS_EVICTION_POOL_SIZE-1; k >= 0; k--) {if (pool[k].key == NULL) continue;de = dictFind(dict,pool[k].key); // 定位目标/* Remove the entry from the pool. */sdsfree(pool[k].key);/* Shift all elements on its right to left. */memmove(pool+k,pool+k+1,sizeof(pool[0])*(REDIS_EVICTION_POOL_SIZE-k-1));/* Clear the element on the right which is empty* since we shifted one position to the left.  */pool[REDIS_EVICTION_POOL_SIZE-1].key = NULL;pool[REDIS_EVICTION_POOL_SIZE-1].idle = 0;/* If the key exists, is our pick. Otherwise it is* a ghost and we need to try the next element. */if (de) {bestkey = dictGetKey(de); // 确定删除键break;} else {/* Ghost... */continue;}}}}/* volatile-ttl */else if (server.maxmemory_policy == EDIS_MAXMEMORY_VOLATILE_TTL) {......}// 最终选定待删除键bestkeyif (bestkey) {long long delta;robj *keyobj = createStringObject(bestkey,sdslenbestkey)); // 目标对象propagateExpire(db,keyobj);latencyStartMonitor(eviction_latency); // 延迟监控开始dbDelete(db,keyobj); // 从db删除对象latencyEndMonitor(eviction_latency);// 延迟监控结束latencyAddSampleIfNeeded("eviction-del",iction_latency); // 延迟采样latencyRemoveNestedEvent(latency,eviction_latency);delta -= (long long) zmalloc_used_memory();mem_freed += delta; // 释放内存计数server.stat_evictedkeys++; // 淘汰key计数,info中可见notifyKeyspaceEvent(REDIS_NOTIFY_EVICTED, "evicted", keyobj, db->id); // 事件通知decrRefCount(keyobj); // 引用计数更新keys_freed++;// 避免删除较多键导致的主从延迟,在循环内同步if (slaves) flushSlavesOutputBuffers();}}
}

Redis 4.0中新增的LFU算法

从Redis4.0开始,新增LFU淘汰机制,提供更好缓存命中率。LFU(Least Frequently Used)通过记录键使用频率来定位最可能淘汰的键。

LFU使用Morris counters计数器占用少量位数来评估每个对象的访问频率,并随时间更新计数器。此机制实现与近似LRU中采样类似。但与LRU不同,LFU提供明确参数来指定计数更新频率。

这两个因子形成一种平衡,通过少量访问 VS 多次访问 的评价标准最终形成对键重要性的评判。

在LRU中,某个键很少被访问,但在刚刚被访问后其被淘汰概率很低,从而出现这类异常持续存在的缓存;相对的,其他可能被访问的键会被淘汰;而LFU中,按访问频次淘汰最少被访问的键。

volatile-lfu:设置过期时间的键按LFU淘汰

allkeys-lfu:所有键按LFU淘汰

 参考:Redis中内存淘汰算法实现 | 小武的博客 


http://www.ppmy.cn/news/335145.html

相关文章

谈高端内存和低端内存

我是看ldd3的第十五章&#xff08;409页&#xff09;时&#xff0c;对用户虚拟地址、物理地址、总线地址、内核逻辑地址、内核虚拟地址区分不了&#xff0c;才搜索资料的。找了几篇blog都没有把问题说清楚&#xff0c;下面这blog解释的还是不错的。 一、高端内存和低端内存的划…

如何保留低端内存

如何保留低端内存 环境 &#xff1a; Red Hat Enterprise Linux (RHEL) 5.x (X86) 在 X86 高内存设备中&#xff0c;当用户进程使用 mlock() 在常规区域分配大量内存时&#xff0c;可重新使用的 lowmem 内存可能会不足&#xff0c;而一些系统呼叫将失败并显示“EAGAIN” 等错…

Redis的内存淘汰策略

Redis的高性能网络IO模型 Redis的高性能网络IO模型_Lucifer Zhao的博客-CSDN博客 Redis的持久化机制 Redis的持久化机制_Lucifer Zhao的博客-CSDN博客 Redis的过期策略 为了保证内存利用率&#xff0c;会把设置了过期时间并且过期的数据进行删除 惰性过期(被动过期): 通过…

windows for cuda cudnn

安装教程&#xff1a; https://blog.csdn.net/David_B/article/details/113576999?spm1001.2101.3001.6650.1&utm_mediumdistribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_default&depth_1-utm_sourcedistribute.pc_relevant.none…

cin和cout的使用

cin 1 cin的使用&#xff1a;2 cin>>a;3 cin和cout 都在std命名空间下4 cin使用“>>”右移运算符表示输入&#xff0c;将">>"右边的内容输入5 例如&#xff0c;6 void qq() {7 int b0;8 cin >> b0;9 …

cudnn cuda 网址

1cudnn cuDNN Archive | NVIDIA Developer 2. CUDA ToolKit的安装&#xff1a; CUDA的下载地址为&#xff1a;CUDA Toolkit Archive | NVIDIA Developer

TL431做比较器该如何理解?

TL431是由美国德州仪器公司&#xff08;TI&#xff09;和Motorola公司生产的2.50~36V可调精密并联稳压器&#xff0c;它是一种具有可调电流输出能力的基准电压源&#xff0c;TL431系列产品包括TL431C、TL431AC、TL431I、TL431AI、TL431M、TL431Y&#xff0c;共6种型号。它们的内…

pytorch使用DCN

pytorch使用DCN 前言正文 前言 关于DCN可形变卷积神经网络相信大家也都不陌生&#xff0c;使用额外的feature map区学习offset&#xff0c;以此达到可形变的效果。感觉和attention比较相似&#xff1f; 但是网络实现的代码版本各不相同&#xff0c;编译环境存在很多难以协调等…