那些年我们一起追过的缓存写法(二)

感谢园子里的同学对上一篇的支持,很高兴楼主的一些经验及想法能够对大家有一些帮助。

上次主要讨论缓存读写这块各种代码实现,本篇就上次的问题继续来,看看那些年折腾过的各种缓存做法。

缓存预热

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

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

可以在启动事件里面刷新

void Application_Start(object sender, EventArgs e)
        {
            //刷新
        }

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

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

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

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

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

多级缓存

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

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

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

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

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

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

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

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

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

线程缓存

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

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

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

public static ThreadLocal<UserScore> localUserInfo = new ThreadLocal<UserScore>();

借助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缓存、反向代理缓存、服务端缓存、也是多层缓存。

总结

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

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

系列目录:

那些年我们一起追过的缓存写法(一)

那些年我们一起追过的缓存写法(二) 

那些年我们一起追过的缓存写法(三) 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小狼的世界

由于版本依赖造成的YUM段错误

最近在服务器(Centos 5.3,64位)上使用YUM,总是提示 Segmentation Fault,无论执行什么命令都是如此,一时不得其解。

14020
来自专栏散尽浮华

由索引节点(inode)爆满引发的问题

关于磁盘空间中索引节点爆满的问题还是挺多的,借此跟大家分享一下: 一、发现问题 在公司一台配置较低的Linux服务器(内存、硬盘比较小)的/data分区内创建...

36080
来自专栏JAVA烂猪皮

大型分布式网站架构:缓存在分布式系统中的应用

缓存是分布式系统中的重要组件,主要解决高并发,大数据场景下,热点数据访问的性能问题。提供高性能的数据快速访问。

18130
来自专栏CSDN技术头条

关于缓存你需要知道的

About Cache 作后端开发的同学,缓存是必备技能。这是你不需要花费太多的精力就能显著提升服务性能的灵丹妙药。前提是你得知道如何使用它,这样才能够最大限度...

23170
来自专栏纯洁的微笑

一次线上问题排查所引发的思考

之前或多或少分享过一些内存模型、对象创建之类的内容,其实大部分人看完都是懵懵懂懂,也不知道这些的实际意义。

13210
来自专栏枕边书

PHP 调用 Go 服务的正确方式 - Unix Domain Sockets

问题 可能是由于经验太少,工作中经常会遇到问题,探究和解决问题的过程总想记录一下,所以我写博客经常是问题驱动,首先介绍一下今天要解决的问题: 服务耦合 我们在开...

395110
来自专栏进击的程序猿

ZooKeeper: Wait-free coordination for Internet-scale systems(笔记)

本文是读ZooKeeper: Wait-free coordination for Internet-scale systems的笔记,从第一手资料了解zook...

12830
来自专栏个人分享

数据集成中间件知识点总结

  数据集成是把不同来源、格式、特点性质的数据在逻辑上或物理上有机地集中,从而为企业提供全面的数据共享。

50410
来自专栏架构师之路

网页端收消息,究竟是推还是拉?

抛开这些技术细节不谈,暂且认为服务端对每一个用户都有一个“待收消息”的队列,里面存放了需要给这个用户的一切消息。

13020
来自专栏IT技术精选文摘

redis架构演变与redis-cluster群集读写方案

redis-cluster是近年来redis架构不断改进中的相对较好的redis高可用方案。本文涉及到近年来redis多实例架构的演变过程,包括普通主从架构(M...

73730

扫码关注云+社区

领取腾讯云代金券