Redis内存淘汰

2024-08-24 07:04
文章标签 内存 redis 淘汰

本文主要是介绍Redis内存淘汰,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Redis内存淘汰

Redis可以存储多少数据

maxmemory配置,默认是注释掉的。

#maxmemory <bytes>

我们可以主动配置maxmemory,maxmemory支持各种单位,默认是字节

maxmemory 1024
maxmemory 1024KB
maxmemory 1024MB
maxmemory 1024GB

当Redis存储超过这个值,就会触发内存淘汰。

淘汰策略

有两个方向,一个是noevicition,默认就是这种策略,如果内存达到maxmemory,则写入操作失败,但不会淘汰原有数据;另一个是多种淘汰策略,主要是LRU、LFU、RANDOM、TTL。

image-20240822215406391

LRU(Least recently used,最近最少使用):尝试回收最长时间未使用的。

LFU(Least Frequently Use,最近最少频率使用):尝试回收最不常用的键。

Random:随机回收键。

TTL:回收过期集合的键,并且优先回收存活时间较短(TTL)的键。

一般四种策略又分为volatile,设置了过期时间的Key;或是allkeys,全部的Key。

选择哪种淘汰算法

一般根据业务需求决定,缓存场景下一般使用的是LRU或LFU。

LRU

什么是LRU

最近最久未使用,即记录每个Key的最近访问时间,维护一个访问时间的数据

Redis的近似LRU

为什么不直接使用LRU

因为对所有数据用一个双向链表维护就是一个巨大的成本,Redis本身就是使用内存的,而内存是又少又珍贵的资源,所以Redis选择实现一个近似LRU。

近似的LRU

LRU模式中,RedisObject中lru字段存储的是被访问时的时间,每次该key被访问就会更新这个字段。

llru字段表示的时间戳越小,代表key空闲的时间越长,越应该被淘汰

为了保证高性能,Redis还缓存了Unix操作系统的时钟。

近似的LRU算法中,在内存不足时就会,进行全局随机采样,来筛选准备淘汰的元素。

步骤为:

1.随机采样n个key,n默认为5

2.根据时间戳淘汰最旧的key

3.判断内存是否不足,不足循环步骤1;反之,退出淘汰

之前说的全局随机采样,也是一个范围性的选择。也就是之前提过的,allkeys或者volatile

淘汰池的优化

近似LRU,最大的优点就是节约了内存。但是它的缺点是,淘汰的key是随机采样的结果,并不是真正的全局最久未访问。

在Redis3.0中,对近似LRU进行了优化:加入淘汰池。

优化后的LRU会维护一个大小为16的候选池,池中的数据按时间进行排序。

步骤:

1.第一次是随机挑选的16个,第一次以后就是随机挑选的一个

2.按访问时间进行排序,并且淘汰最久未访问的(一次只淘汰一个,剩下的都在池中)

3.判断是否继续

LRU优化后的对比

image-20240822222328915

浅灰色是被淘汰的数据

灰色是没有被淘汰的老数据

绿色是新加入的数据

我们几乎可以认为Redis的近似LRU已经达到正常LRU的水准了。

LFU

什么是LFU

最不频繁淘汰算法,优先淘汰活跃最低,使用频率最低的。

为什么引入LFU

Redis在4.0版本后引入了LFU算法,为什么?

因为在部分场景下,只根据最近访问,不谈频率得不到我们希望的结果。

比如,有两个键key1、key2,之前9次一直在访问key1,第10次访问了key2,第10次后触发了内存淘汰,那你觉得该淘汰key1还是key2?

如果我们使用LRU,那就是淘汰key1;如果我们使用LFU,那就是淘汰key2。

但是这种场景下,一般我们会期望按频率来进行淘汰,于是就有了LFU

Redis的LFU

策略

我们之前提供Redis的RedisObject中有个字段是lru,其实LFU也是用这个字段来实现的。

LFU和LRU两种策略是一种互斥关系,是不会同时开启的。LFU将这个字段(lru字段24位)拆分为两部分,高16位存储ldt,也就是Last Decrement Time,低8位存储logc logistic Counter。

image-20240823110848798

一个key是否活跃是根据这两个字段决定的。如果一个key,原来访问计数是255,但是一年没访问就会变成0(举例,并不一定是这样);如果一个key,频频被访问,它的访问计数会逐渐变大。

源码中,有部分代码证明了LFU和LRU是共用lru字段的。

#define LFU_INIT_VAL 5
robj *createObject(int type, void *ptr) {robj *o = zmalloc(sizeof(*o));//...//o的初始化//...if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {o->lru = (LFUGetTimeMinutex()<<8) | LFU_INIT_VAL;}  else {o->lru = LRU_CLOCK();}return o'
}

代码中也说了,如果达到maxmemory,并且策略为LFU,前16位设置时间戳,后8位设置访问频率;否则设置lru当前时间戳。

访问频率衰减

redis.conf文件中,有一项配置为lfu_decay_time,默认值为1,表示每一分钟衰减一次。也就是上一次访问时间距离当前时间的分钟数。

lfu_decay_time 1
频率更新

访问计数的频率是一定概率增加的,次数不到5次,一定增加;如果大于5,小于255,一定概率增加;次数越大,越困难。

当然这也是有配置项的,lfu_log_factor被设置的越大,增加难度就越大,配置为0,每次会必然加1,上限为255(8位)。

void updateLFU(robj *val) {unsigned long counter = LFUDecrAndReturn(val);counter = LFULogIncr(counter);val->lru = (LFUGetTimeMinutes()<<8) | counter;
}

时间更新到高16位,次数更新到低8位。

这篇关于Redis内存淘汰的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101782

相关文章

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

Python内存管理机制之垃圾回收与引用计数操作全过程

《Python内存管理机制之垃圾回收与引用计数操作全过程》SQLAlchemy是Python中最流行的ORM(对象关系映射)框架之一,它提供了高效且灵活的数据库操作方式,本文将介绍如何使用SQLAlc... 目录安装核心概念连接数据库定义数据模型创建数据库表基本CRUD操作创建数据读取数据更新数据删除数据查

Redis高性能Key-Value存储与缓存利器常见解决方案

《Redis高性能Key-Value存储与缓存利器常见解决方案》Redis是高性能内存Key-Value存储系统,支持丰富数据类型与持久化方案(RDB/AOF),本文给大家介绍Redis高性能Key-... 目录Redis:高性能Key-Value存储与缓存利器什么是Redis?为什么选择Redis?Red

k8s容器放开锁内存限制问题

《k8s容器放开锁内存限制问题》nccl-test容器运行mpirun时因NCCL_BUFFSIZE过大导致OOM,需通过修改docker服务配置文件,将LimitMEMLOCK设为infinity并... 目录问题问题确认放开容器max locked memory限制总结参考:https://Access

Redis 的 SUBSCRIBE命令详解

《Redis的SUBSCRIBE命令详解》Redis的SUBSCRIBE命令用于订阅一个或多个频道,以便接收发送到这些频道的消息,本文给大家介绍Redis的SUBSCRIBE命令,感兴趣的朋友跟随... 目录基本语法工作原理示例消息格式相关命令python 示例Redis 的 SUBSCRIBE 命令用于订

sky-take-out项目中Redis的使用示例详解

《sky-take-out项目中Redis的使用示例详解》SpringCache是Spring的缓存抽象层,通过注解简化缓存管理,支持Redis等提供者,适用于方法结果缓存、更新和删除操作,但无法实现... 目录Spring Cache主要特性核心注解1.@Cacheable2.@CachePut3.@Ca