Redis内存策略

这篇具有很好参考价值的文章主要介绍了Redis内存策略。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Redis内存策略

Redis是基于内存存储,所以其性能很强。但单节点的Redis内存不宜过大,否则会影响持久化或主从同步性能。

可以手动修改配置文件来设置Redis的最大内存

# 格式: maxmemory <bytes>
maxmemory 1gb

如果内存使用达到了上限,就无法存储更多的数据了。

Redis为尽量避免内存达到上限,提供了两种策略:过期策略淘汰策略


过期策略

在Redis缓存中,可以通过expire命令为redis的key设置TTL(过期时间,或存活时间)。

Redis内存策略,redis,后端学习,redis,mybatis,数据库

当key的TTL到期之后,再次访问key是返回的值为nil(空),说明这个key就已经不存在了,其对应的内存也得到了释放,从而起到了内存回收的目的。

DB结构

Redis本身就是一个很经典的key-value内存存储数据库,因此所有的key、value都保存在Dict结构中。不过在其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;

结构流程图:

Redis内存策略,redis,后端学习,redis,mybatis,数据库


惰性删除

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

// 查找一个key执行写操作
robj *lookupKeyWriteWithFlags(redisDb *db, robj *key, int flags) {
    // 检查key是否过期
    expireIfNeeded(db,key);
    return lookupKey(db,key,flags);
}
// 查找一个key执行读操作
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
    robj *val;
    // 检查key是否过期    if (expireIfNeeded(db,key) == 1) {
        // ...略
    }
    return NULL;
}

int expireIfNeeded(redisDb *db, robj *key) {
    // 判断是否过期,如果未过期直接结束并返回0
    if (!keyIsExpired(db,key)) return 0;
    // ... 略
    // 删除过期key
    deleteExpiredKeyAndPropagate(db,key);
    return 1;
}

这种删除策略,会存在一个问题:如果一个key过期了就再也没有被访问过,则这个key就永远不会被删除。在极端情况下,当大量的key出现这种情况,也会对内存造成很大的压力。


周期删除

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

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

    // server.c
    void initServer(void){
        // ...
        // 创建定时器,关联回调函数serverCron,处理周期取决于server.hz,默认10
        aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) 
    }
    
    // server.c
    int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
        // 更新lruclock到当前时间,为后期的LRU和LFU做准备
        unsigned int lruclock = getLRUClock();
        atomicSet(server.lruclock,lruclock);
        // 执行database的数据清理,例如过期key处理
        databasesCron();
    }
    
    void databasesCron(void) {
        // 尝试清理部分过期key,清理模式默认为SLOW
        activeExpireCycle(
              ACTIVE_EXPIRE_CYCLE_SLOW);
    }
    
  • Redis的每个事件循环前会调用beforeSleep()函数,执行过期key清理,模式为FAST。

    void beforeSleep(struct aeEventLoop *eventLoop){
        // ...
        // 尝试清理部分过期key,清理模式默认为FAST
        activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
    }
    
    void aeMain(aeEventLoop *eventloop){
        eventLoop->stop = 0;
        while(!eventLoop->stop){
            // beforeSleep() --> Fast模式快速清理
            // n = aeApiPoll()
            // 如果n > 0,FD就绪,处理IO事件。
            // 如果到了执行时间,则调用serverCron() --> SLOW模式清理
        }
    }
    

    周期清理的两种模式:

    SLOW模式规则:

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

    ② 执行清理耗时不超过一次执行周期的25%.默认slow模式耗时不超过25ms。

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

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

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

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

    ② 执行清理耗时不超过1ms。

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

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


淘汰策略

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

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

int processCommand(client *c) {
    // 如果服务器设置了server.maxmemory属性,并且并未有执行lua脚本
    if (server.maxmemory && !server.lua_timedout) {
        // 尝试进行内存淘汰performEvictions
        int out_of_memory = (performEvictions() == EVICT_FAIL);
        // ...
        if (out_of_memory && reject_cmd_on_oom) {
            rejectCommand(c, shared.oomerr);
            return C_OK;
        }
        // ....
    }
}

Redis支持8种不同策略来选择要删除的key:

  • noeviction:不淘汰任何key,但是内存满时不允许写入新数据(默认)。
  • volatile-ttl:对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰。
  • allkeys-random:对全体key ,随机进行淘汰。也就是直接从db->dict中随机挑选。
  • volatile-random:对设置了TTL的key ,随机进行淘汰。也就是从db->expires中随机挑选。
  • allkeys-lru: 对全体key,基于LRU算法进行淘汰。
  • volatile-lru: 对设置了TTL的key,基于LRU算法进行淘汰。
  • allkeys-lfu: 对全体key,基于LFU算法进行淘汰。
  • volatile-lfu: 对设置了TTL的key,基于LFI算法进行淘汰。

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

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


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;

逻辑访问次数:并不是每次key被访问都计数,而是通过下面的步骤计算得来:

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

淘汰策略流程图:

Redis内存策略,redis,后端学习,redis,mybatis,数据库文章来源地址https://www.toymoban.com/news/detail-683575.html

到了这里,关于Redis内存策略的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【虹科分享】Redis 不仅仅是内存数据库

    Redis难道仅仅是内存数据库吗?No!加速金融交易!让视频游戏云服务快得令人难以置信!实现实时在线购买! 让我们从这些例子开始,探索一些 Redis可以实现的其他可能性! 文章速览: 基于实时分析和库存管理做出更明智的决策 实现数据和视频的流畅播放 提供关键数据的故障

    2024年02月06日
    浏览(42)
  • Go重写Redis中间件 - Go实现内存数据库

    前面我们实现了一个简单的回发Redis,这里我们要实现一个真正的Redis内核 实现底层Dict数据结构 新建一个datastruct文件夹,放一些我们要用的数据结构,比如Redis的核心起始就是一个map,再新建一个包实现这个map或者叫字典,字典的底层使用的就是map dict.go 写一个Dict接口定义

    2024年02月11日
    浏览(48)
  • Redis内存空间预估与内存优化策略:保障数据安全与性能的架构实践AIGC/AI绘画/chatGPT/SD/MJ

    摘要: 在现代软件架构中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、会话存储和消息队列等场景。然而,Redis的内存占用问题一直是开发者关注的焦点。本文将介绍如何准确预估Redis所占内存空间,并提供一些内存优化策略,以避免内存占用过多导致数据丢失的

    2024年02月11日
    浏览(40)
  • Redis内存策略

    Redis是基于内存存储,所以其性能很强。但单节点的Redis内存不宜过大,否则会影响持久化或主从同步性能。 可以手动修改配置文件来设置Redis的最大内存 如果内存使用达到了上限,就无法存储更多的数据了。 Redis为尽量避免内存达到上限,提供了两种策略: 过期策略 、 淘

    2024年02月10日
    浏览(28)
  • Redis 内存淘汰策略详解

    Redis 是一款高性能的非关系型数据库,它支持多种数据结构,如字符串、哈希、列表、集合、有序集合和 HyperLogLog。Redis 可以用于缓存、消息队列、应用程序中的数据结构存储等场景,它的优点是响应速度快、支持丰富的数据结构和扩展性好。 Redis 将所有数据都存储在内存中

    2024年02月10日
    浏览(55)
  • Redis的内存淘汰策略

    Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。 noeviction :当内存不足以容纳新写入数据时,新写入操作会报错。 allkeys-lru :当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用

    2024年02月10日
    浏览(34)
  • Redis内存兜底策略——内存淘汰及回收机制

    Redis内存淘汰及回收策略都是Redis 内存优化兜底 的策略,那它们是如何进行 兜底 的呢?先来说明一下什么是内存淘汰和内存回收策略: Redis内存淘汰:当Redis的内存使用 超过配置 的限制时,根据一定的策略删除一些键,以 释放内存空间 Redis内存回收:Redis通过 定期删除 和

    2024年02月06日
    浏览(38)
  • Redis 原理缓存过期、一致性hash、雪崩、穿透、并发、布隆、缓存更新策略、缓存数据库一致性

    redis的过期策略可以通过配置文件进行配置 redis会把设置了过期时间的key放在单独的字典中,定时遍历来删除到期的key。 1).每100ms从过期字典中 随机挑选20个,把其中过期的key删除; 2).如果过期的key占比超过1/4,重复步骤1 为了保证不会循环过度,导致卡顿,扫描时间上限

    2024年02月08日
    浏览(56)
  • redis 7.x 内存过期淘汰策略

    1.查看redis默认内存大小 config  get  maxmemory config set  maxmemory    1024 注意:在64-bit系统下,maxmemory设置为0表示不限制redis的内存使用。 LRU: 最近最少使用页面置换算法 ,查看页面最后一次被使用到发生调度的时间长度,首先淘汰最长时间未被使用的页面。 LFU:最近最不经常

    2024年02月07日
    浏览(44)
  • Redis内存碎片:深度解析与优化策略

    本文已收录至GitHub,推荐阅读 👉 Java随想录 微信公众号:Java随想录 原创不易,注重版权。转载请注明原作者和原文链接 目录 内存碎片如何产生的 内存分配器 怎么看是否有内存碎片 碎片率的意义 清理内存碎片 低于4.0-RC3版本的Redis 高于4.0-RC3版本的Redis 在我们探究和优化

    2024年02月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包