Redis 内存满了怎么办?

微信公众号:moon聊技术
本文约5600字,完整阅读大概会花费你「15分钟」左右的时间
[如果你觉得文章对你有帮助,欢迎关注,点赞,转发]

简介

我们知道redis是一个非常常用的内存型数据库,数据从内存中读取是它非常高效的原因之一,那么但是如果有一天,「redis分配的内存满了怎么办」?遇到这个面试题不要慌,这种问题我们分为两角度回答就可以:

  • 「redis会怎么做」
  • 「我们可以怎么做」

增加redis可用内存

这种方法很暴力,也很好用,我们直接通过增加redis的可用内存就可以了, 有两种方式

  • 「通过配置文件配置」

    /* 
    *
    * 这个函数是 EXPIRE 、 PEXPIRE 、 EXPIREAT 和 PEXPIREAT 命令的底层实现函数。
    *
    * 命令的第二个参数可能是绝对值,也可能是相对值。
    * 当执行 *AT 命令时, basetime 为 0 ,在其他情况下,它保存的就是当前的绝对时间。
    *
    * unit 用于指定 argv[2] (传入过期时间)的格式,
    * 它可以是 UNIT_SECONDS 或 UNIT_MILLISECONDS ,
    * basetime 参数则总是毫秒格式的。
    */
    void expireGenericCommand(redisClient *c, long long basetime, int unit) {
       robj *key = c->argv[1], *param = c->argv[2];
       long long when; /* unix time in milliseconds when the key will expire. */

       // 取出 when 参数
       if (getLongLongFromObjectOrReply(c, param, &when, NULL) != REDIS_OK)
           return;

       // 如果传入的过期时间是以秒为单位的,那么将它转换为毫秒
       if (unit == UNIT_SECONDS) when *= 1000;
       when += basetime;

       /* No key, return zero. */
       // 取出键
       if (lookupKeyRead(c->db,key) == NULL) {
           addReply(c,shared.czero);
           return;
       }

       /* 
        * 在载入数据时,或者服务器为附属节点时,
        * 即使 EXPIRE 的 TTL 为负数,或者 EXPIREAT 提供的时间戳已经过期,
        * 服务器也不会主动删除这个键,而是等待主节点发来显式的 DEL 命令。
        *
        * 程序会继续将(一个可能已经过期的 TTL)设置为键的过期时间,
        * 并且等待主节点发来 DEL 命令。
        */
       if (when <= mstime() && !server.loading && !server.masterhost) {

           // when 提供的时间已经过期,服务器为主节点,并且没在载入数据

           robj *aux;

           redisAssertWithInfo(c,key,dbDelete(c->db,key));
           server.dirty++;

           /* Replicate/AOF this as an explicit DEL. */
           // 传播 DEL 命令
           aux = createStringObject("DEL",3);

           rewriteClientCommandVector(c,2,aux,key);
           decrRefCount(aux);

           signalModifiedKey(c->db,key);
           notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);

           addReply(c, shared.cone);

           return;
       } else {

           // 设置键的过期时间
           // 如果服务器为附属节点,或者服务器正在载入,
           // 那么这个 when 有可能已经过期的
           setExpire(c->db,key,when);

           addReply(c,shared.cone);

           signalModifiedKey(c->db,key);
           notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"expire",key,c->db->id);

           server.dirty++;

           return;
       }
    }

     setExpire函数主要是对db->expires中的key对应的dictEntry设置过期时间。

    /*
    * 将键 key 的过期时间设为 when
    */
    void setExpire(redisDb *db, robj *key, long long when) {

       dictEntry *kde, *de;

       /* Reuse the sds from the main dict in the expire dict */
       // 取出键
       kde = dictFind(db->dict,key->ptr);

       redisAssertWithInfo(NULL,key,kde != NULL);

       // 根据键取出键的过期时间
       de = dictReplaceRaw(db->expires,dictGetKey(kde));

       // 设置键的过期时间
       // 这里是直接使用整数值来保存过期时间,不是用 INT 编码的 String 对象
       dictSetSignedIntegerVal(de,when);
    }

    redis什么时候执行淘汰策略?

    在redis种有三种删除的操作此策略

    • 定时删除:对于设有过期时间的key,时间到了,定时器任务立即执行删除
      • 因为要维护一个定时器,所以就会占用cpu资源,尤其是有过期时间的redis键越来越多损耗的性能就会线性上升
    • 惰性删除:每次只有再访问key的时候,才会检查key的过期时间,若是已经过期了就执行删除。
      • 这种情况只有在访问的时候才会删除,所以有可能有些过期的redis键一直不会被访问,就会一直占用redis内存
    • 定期删除:每隔一段时间,就会检查删除掉过期的key。
      • 这种方案相当于上述两种方案的折中,通过最合理控制删除的时间间隔来删除key,减少对cpu的资源的占用消耗,使删除操作合理化。

    巨人的肩膀
     https://www.jianshu.com/p/53083f5f2ddc  https://zhuanlan.zhihu.com/p/265597517

    Redis 内存满了怎么办?

    七种分布式事务的解决方案,一次讲给你听


    Redis 内存满了怎么办?

    妹妹10分钟就玩懂了零拷贝和NIO,也太强了


    Redis 内存满了怎么办?

    redis持久化怎么选?成年人从来不做选择…



    Redis 内存满了怎么办?


    确定不勾搭一下moon吗?

    玩玩技术,聊聊人生,看看生活,搞搞理想!

    回复666  还免费送你一份面试大礼包~

    我真贴心~

    本篇文章来源于微信公众号: 龙台的技术笔记

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/10174.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!