Redis过期–淘汰机制的解析和内存占用过高的解决方案「建议收藏」

Redis过期–淘汰机制的解析和内存占用过高的解决方案

大家好,又见面了,我是全栈君。

点击上方“码农编程进阶笔记”,选择“置顶或者星标

优质文章第一时间送达!

Redis过期--淘汰机制的解析和内存占用过高的解决方案「建议收藏」

Redis在我们平时的开发或者练习的时候,往往很容易忽略一个问题,那就是我们的Redis内存占满的问题。但是在真是的商业开发中,Redis的实际占满是真正会存在这样的问题的。那么如果Redis在某一刻占满内存,我们又没有对它进行相应的设置它会出现什么情况呢?会不会导致我们整个因为使用Redis而整个业务垮掉?

什么是Redis淘汰机制

Redis内存淘汰机制其实简单讲就是将过期的数据或者很久没有访问,或者在一段时间内很少有访问的数据进行删除。它分为很多中,有主动的数据淘汰,如:用户设定过期时间。有被动的淘汰,比如:Redis数据占满了内存,这个时候就会将过期的数据或者很久没有访问的数据删除掉。

Redis的淘汰有哪些类型

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

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

  定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)

定时过期的问题:缓存雪崩

很多人可能对这个词很熟悉,因为有很多的商业案例展示了血淋淋的教训,但是也有一部分人估计没有接触过。缓存雪崩其实也不是什么新词,它主要的引起原因就是指缓存中数据大批量的到过期时间。定时过期它本身就有一个缺点,那就是会占用大量的CPU资源,如果我们主动设置过期时间的键过多,在同一时间过期,很有可能就会造就我们Redis挂掉。但是这并不是最可怕的,雪崩不仅仅影响自己,还在我们的业务中影响数据库。因为我们很多业务设计都是在我们Redis的数据过期之后,从新查询数据库,但我们Redis主动批量过期的时候,会有大量的请求发送到我们的数据库,很有可能导致我们的数据库也挂掉。这才是最大的问题所在。

解决方案:

  • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。

  • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。

  • 设置热点数据永远不过期。

从几种淘汰策略中其实我们可以看到基本的一些问题所在,所以我们在使用缓存的时候最好有一个全面的了解和全面的考虑应对。在实际开发中,我们更应该多去关注的和了解的是定期过期,因为它涉及真实开发中的一些问题。所以我们应该提前设置好。

怎么设置定期过期最大使用内存

定期过期的最大内存设置在我们的redis.conf文件中,我们可以在该文件中看到这个配置:maxmemory <bytes>,但是这个配置一般都是注释掉的,也就是说安装之后如果我们没有主动对他进行配置,那么他就不会有默认大小值。对应的它不设置的情况下,那么它可以使用多少的内存空间呢?这个跟系统有关。如果说我们将Redis安装在32位的系统上,它的最大使用内存空间应该是在3G左右,如果是64位的系统,那么可以将我们的内存占满。当然如果真正占满内存,这是一件比较恶劣的事情,不仅仅访问Redis的时候,我们不能在进行写的操作,而且我们系统本身的其他操作也会受到限制。所以我们可以采用命令来对它进行一个初始化的设置

config set maxmemory 268435456

使用命令进行设置之后我们需要重启Redis才能生效。当然我们也可以直接找到Redis的安装目录,然后使用vi命令,直接更改配置文件中的对应的该内容,更改完之后,重启即可。

定期过期的淘汰策略

  volatile-lru:根据LRU算法生成的过期时间来删除。

 allkeys-lru:根据LRU算法删除任何key

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

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

volatile-random:根据过期设置来随机删除key。

 allkeys-random:无差别随机删。

 volatile-ttl:根据最近过期时间来删除(辅以TTL)

noeviction:谁也不删,直接在写操作时返回错误。

随机淘汰策略

随机找hash桶再次hash指定位置的dictEntry即可。就是在场景REDIS_MAXMEMORY_VOLATILE_RANDOM和REDIS_MAXMEMORY_ALLKEYS_LRU情况下的待淘汰的key。我们可以一观它的源码:

dictEntry *dictGetRandomKey(dict *d)
{
    dictEntry *he, *orighe;
    unsigned int h;
    int listlen, listele;
 
    if (dictSize(d) == 0) return NULL;
 
    if (dictIsRehashing(d)) _dictRehashStep(d);
 
    if (dictIsRehashing(d)) {
        // T = O(N)
        do {
            h = random() % (d->ht[0].size+d->ht[1].size);
            he = (h >= d->ht[0].size) ? d->ht[1].table[h - d->ht[0].size] :
                                      d->ht[0].table[h];
        } while(he == NULL);
    } else {
        // T = O(N)
        do {
            h = random() & d->ht[0].sizemask;
            he = d->ht[0].table[h];
        } while(he == NULL);
    }
 
    /* Now we found a non empty bucket, but it is a linked
     * list and we need to get a random element from the list.
     * The only sane way to do so is counting the elements and
     * select a random index. */
    listlen = 0;
    orighe = he;
    while(he) {
        he = he->next;
        listlen++;
    }
    listele = random() % listlen;
    he = orighe;
    // T = O(1)
    while(listele--) he = he->next;
 
    return he;
}

TTL时间淘汰

for (k = 0; k < server.maxmemory_samples; k++) {
    sds thiskey;
    long thisval;

    de = dictGetRandomKey(dict);
    thiskey = dictGetKey(de);
    thisval = (long) dictGetVal(de);

    /* Expire sooner (minor expire unix timestamp) is better
     * candidate for deletion */
    if (bestkey == NULL || thisval < bestval) {
        bestkey = thiskey;
        bestval = thisval;
    }
}

更多源码,请参考redis官网。这里只是简单的展示两种。我们可以根据这样的代码来对我们的redis的定期过期做一个合理的配置

Redis过期--淘汰机制的解析和内存占用过高的解决方案「建议收藏」

                来都来了,点个在看再走吧~~~Redis过期--淘汰机制的解析和内存占用过高的解决方案「建议收藏」

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

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/112011.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • httprunner3源码解读(4)parser.py「建议收藏」

    httprunner3源码解读(4)parser.py「建议收藏」源码结构目录可以看到此模块定义了4个属性和12个函数,我们依次来讲解属性源码分析#匹配http://或https://absolute_http_url_regexp=re.compil

    2022年8月7日
    6
  • 线程池面试题一般会怎么问?线程池面试题总结及答案整理

    线程池面试题一般会怎么问?线程池面试题总结及答案整理对于广大程序员来说,线程池一定不会陌生,因为大部分程序员面试时总会被问到关于线程池的问题,今天总结了一些关于线程池的各种面试可能问到的题目,希望对大家有所帮助。一、线程池是什么?答:线程池,是一种多线程处理形式,在处理过程中将任务添加到队列中,然后在创建线程后自动启动这些任务。比如把线程池看成一个容器,集中管理线程。线程使用完不会销毁,会先储存在线程池中。二、线程池有几种?答:常见的线程池有四种。newCachedThreadPool创建一个可缓存的线程池,如果线程池长度超过处理需要,

    2022年5月5日
    47
  • Java的in.nextInt()和in.nextLine()方法的具体内涵[通俗易懂]

    Java的in.nextInt()和in.nextLine()方法的具体内涵[通俗易懂]本人也是刚开始学习java语言,在学习的过程中,老师让我们做一个模拟学生学籍管理系统的小程序。因为刚开始,做的是比较简单的,用switch语句做界面,然后配合Scanner接收输入的数字进行跳转,完成各类操作。因为跳转时输入的是数字,而跳转后的操作要输入字符串,比如:“选择1添加学生信息…输入添加学生的姓名…”这类的操作在测试的时候总是无法输入字符串像这个样子,先用nextInt()再用…

    2022年5月5日
    81
  • Android View 深度分析requestLayout、invalidate与postInvalidate「建议收藏」

    Android View 深度分析requestLayout、invalidate与postInvalidate「建议收藏」前言前几篇文章中,笔者对View的三大工作流程进行了详细分析,而这篇文章则详细讲述与三大工作流程密切相关的两个方法,分别是requestLayout和invalidate,如果对Viwe的三个工作流程不熟悉的读者,可以先看看前几篇文章,以便能更容易理解这篇文章的内容。

    2022年6月2日
    35
  • Go如何发送广播包

    Go如何发送广播包

    2022年1月6日
    55
  • 小明加密通道进入_「成都全接触」最新!成都8条地铁进展来了!年底还有5条铁路、9条通道!…「建议收藏」

    小明加密通道进入_「成都全接触」最新!成都8条地铁进展来了!年底还有5条铁路、9条通道!…「建议收藏」友情提示:2020余额已不足四分之一大家关心的8条地铁线路也有了最新进度其中包括5条预计今年开通3条全新路线、2条机场快速线一起来看看有没有路过你家门口的(内含路线图)-10号线三期-最新进展:全线5个车站已全部打围,正在开展绿化迁移及管线迁改等前期工作,其中2个车站进行围护桩施工。2号线、10号线三期、17号线三线换乘车站——人民公园站已于10月15日首桩开钻。10号线三期工程北起人…

    2022年6月10日
    691

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号