美文网首页Java成长之路互联网科技程序员
浅谈缓存写法(二):多级缓存、分布式缓存

浅谈缓存写法(二):多级缓存、分布式缓存

作者: Java_老男孩 | 来源:发表于2019-04-22 17:20 被阅读71次

    缓存预热

    上次有同学问过,在第一次加载时缓存都为空,怎么进行预热。

    单机Web情况下一般使用RunTimeCache,这种情况下:

    可以在启动事件里面刷新

    <pre style="margin:0px;
        padding:0px;
        white-space:pre-wrap;
        overflow-wrap:break-word;
        font-family:&quot;
        Courier New&quot;
        !important;
        font-size:12px !important;
        ">void Application_Start(object sender,EventArgs e) {
        //刷新
    }
    </pre>
    

    另外可以单写个刷新缓存页面,上线后手动刷新下或发布时自动调用刷新,再或者由用户自行触发。

    分布式缓存(Redis、Memcached)情况下:

    比如在几十台服务器缓存时,单刷满缓存都需要不少一段时间。

    这种预热就复杂一些,有的会单写个应用程序去跑,也有的会单写套框架机制去处理(更智能化)。

    其目的是在系统上线之前,所有的缓存都预先加载完毕。

    多级缓存

    计算机结构中CPU和内存之间一般都配有一级缓存、二级缓存来增加交换速度。

    这样当CPU调用大量数据时,就可避开内存直接从CPU缓存中调用,加快读取速度。

    根据CPU缓存得出多级缓存的特点:

    1:每一级缓存中储存的是下一级缓存的一部分。

    2:读取速度按级别依次递减,成本也依次递减,容量依次递增。

    3:当前级别未命中时,才会去下一级寻找。

    而在企业应用级开发中,使用多级缓存是同样的目的及设计,只是粒度更粗,更灵活。

    根据速度依次排列lv1-lv6的缓存类型图:

    3级缓存的命中流程图例子:

    线程缓存

    Web应用是天生的多线程开发,对于一些公共资源必须考虑线程安全,为止不得不通过锁来保证数据的完整性和正确性。

    在实际当中一台web服务器至少也得处理成百上千的请求,想一想在业务复杂的处理流程,函数每调用一次都得锁一下,对服务器也是个不小的浪费。

    而通过线程缓存,可以让当前处理用户请求的线程只拿自己需要的数据。

    <pre style="margin: 0px; 
                padding: 0px; 
                white-space: pre-wrap;
                overflow-wrap: break-word; 
                font-family: &quot;
                Courier New&quot; 
                !important; 
                font-size: 12px !important;"
    >
    public static ThreadLocal<UserScore> localUserInfo = new ThreadLocal<UserScore>();
    </pre>
    

    借助Net提供的线程本地变量,可以在请求入口去拉取当前用户的数据。

    在之后线程整个生命周期里面,业务逻辑可以毫无顾虑的使用这些数据,而不需要考虑线程安全。

    因为不用重新拿新缓存数据,所以也不用担心数据撕裂的问题。

    其当前线程周期里面的数据是完整无误的,只有用户第二次发起请求才会重新去拿新数据。

    这样就能提高不少服务器吞吐量,注意要在线程的出口处销毁数据。

    内存缓存

    无论是远程数据库读取,还是缓存服务器读取。避免不了要跨进程,跨网络通信,有的还跨机房。

    而应用程序频繁读写,对Web、DB服务器都是个不小的消耗,速度相较内存也慢的多。

    代码上加锁、异步,甚至加服务器在内,都不是一个很好的办法。因为加载速度,对用户体验非常重要。


    所以在有要求的项目中使用本地内存做二级缓存,是非常有必要的。目的就是1:抗并发,2:加快读取速度。

    有个著名的缓存五分钟法则法则,就是说如果一个数据频繁被访问,那么就应该放内存中。

    举个例子: 有100并发过来,加锁会导致前端99线程等候,这个99线程等候着,其实是一直在消耗Web服务器资源。不加就是缓存雪崩。

    如果每分钟拉取一份缓存,缓存到内存,这样99线程等候时间极大缩短。

    文件缓存

    相对于内存,硬盘容量大,速度相较于走网络还更快。

    所以我们完全可以把一些不经常变更,放在内存又比较浪费的数据缓存到本地硬盘。

    比如使用sqlite一些文件数据库,我们很容易做到。

    分布式缓存

    基于内存缓存的redis、memcached等。

    基于文件nosql的Casssandra、mongodb等。

    redis、memcached是主流的分布式内存缓存,也是应用和DB中间最大的缓存层。

    nosql这类的其实不单单只是做缓存用了,完全用在一些非核心业务的DB层了。

    DB缓存

    这一层DB主要是缓存由原始数据计算出的结果,从而避免由Web程序通过SQL或在使用中直接计算。

    当然也可以把计算好的数据,存储到redis中当缓存。

    多层缓存

    多层缓存概念在很多地方都用到过:

    1:上面介绍的多级缓存就是一种,把内容根据读取频率,分不同的等级、不同的层次进行存储,频率越高离查询越近。

    2:还一种多层是缓存索引的做法,类似B树查找,这样能提高检索效率。

    3:从架构上来说浏览器缓存、CDN缓存、反向代理缓存、服务端缓存、也是多层缓存。

    总结

    在使用上大家根据实际场景,进行各种组合搭配。本篇谈的比较理论些,有些内容细节没展开。

    比如分布式缓存的使用,缓存置换策略及算法,缓存过期机制等。


    喜欢这篇文章的朋友可以点个喜欢,也可以关注一下我的个人专题:Java成长之路

    针对于上面所涉及到的知识点我总结出了有1到5年开发经验的程序员在面试中涉及到的绝大部分架构面试题及答案做成了文档和架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习,也可以关注我一下以后会有更多干货分享。

    资料获取方式: QQ群搜索“708-701-457” 即可免费领取



    相关文章

      网友评论

        本文标题:浅谈缓存写法(二):多级缓存、分布式缓存

        本文链接:https://www.haomeiwen.com/subject/shoqgqtx.html