37

高速输出-我们戏说缓存 - Ron.Liang

 4 years ago
source link: https://www.cnblogs.com/viter/p/11080160.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

缓存要解决的问题是速度的问题,使用缓存的目的是为了减少对物理资源的访问,缓存大量的应用在软硬件的方方面面,从 CPU 到硬盘,就应用了 一级缓存、二级缓存,少部分高速缓存和大量低速缓存相结合,以提高 CPU 的计算能力,本文讲的主要是系统集成项目中的软件级别的缓存。

缓存因果图
26882-20190624231056694-811798014.png

缓存在现代系统中的位置可以说是举足轻重,不是可有可无的问题了,而是怎么样用好的问题。怎么样讲好缓存这个话题,我思考了很久;如果是生搬硬套,我估计我肯定是凉凉,但要是上来就一顿代码操作,显得字太多,各位看官老爷也是要喷死我的(你们喷我算我赢)。各位看官就当故事随便看看就好了。

客户端缓存

小明同学是一个大学生,每个月都会从爸爸那里领取生活费,由于爸爸给的生活费比较充裕,他就将一部分存了起来,周而复始,固定频率,这就是浏览器网页缓存;有一天,他接到爸爸的一个电话,说每个月给现金,我总是从银行拿也不方便,这样,咱给存银行卡里头,但是说好了,每个月1号的时候转1000块进去,3号之前可以领取,过时不侯。这就是 Cookie!小明说爸,这时间太紧迫了,我万一太过于专心学习忘记取钱那你儿子可是要饿死的吖,到时候没人给你养老送终事儿就大了。他爸爸经过深思熟虑后,决定放开取现时间的限制:行,你想什么时候取都成,就是别把卡给弄掉了就行。这就是LocalStorage/IndexDB,浏览器本地存储。如果银行卡掉了(浏览器重装,删库跑路),那还得找爸爸。

服务器缓存

我们本次讨论的重点就是服务器缓存,对于小明的爸爸来说,每次给小明生活费之前都要到银行(数据库)去取钱出来,实在是太麻烦,不如提前把钱取出来准备好,每次取半年的钱出来放家里保险箱里(缓存),小明申请生活费的时候,直接给他就好了,节约时间效率又高,唯一的问题就是可能没那么安全,有可能被小偷把钱给偷了(缓存更新),然后就是半年时间过后再重新取一笔出来(缓存过期策略)。

静态对象缓存

静态对象也是一种特殊的缓存,静态对象作用于程序的整个生命周期中。需要注意的是,静态对象不会被 GC 回收 ,但是,如果静态对象被多次引用覆盖,那么之前的引用就有可能被 GC 回收。这就好像,小明在向爸爸领取生活费的时候,发现这次领到手的钱实在是太破旧了,都不好意思花出去,爸爸只好重新给了另一份。

会话级缓存

在 Web 站点中,Session 是私有制的,各个 Session 之间是不会共享内存对象的,我们可以利用这个特性(在Asp.NET 时代常用)来暂时保存一些数据,例如用户购物车。还是以小明的需求为例子,小明下面还有一个妹妹,妹妹每个月都可以从爸爸那里多领取200元生活费,看到妹妹的资源这么好,小明愤愤不平,就像妹妹提议共享生活费,一家人一起用,多好吖!结果小明被爸爸揍了一顿,还收回了部分生活费。

进程级别缓存

基本上每个应用程序都具有本地缓存的能力,在 Asp.NET 中就有 MemoryCache ,也叫做进程级缓存(本地缓存),MemoryCache 和 分布式缓存的作用基本一致,所不同的是,本地缓存在应用程序停止后就会被释放掉,无法进行持久存储。就好像,小明在上大学期间,每个月都是生活费的,但是到暑假的时候就没有了(只能靠苦逼的暑期工挣点生活费啊)。

分布式缓存

分布式缓存是个好东西,目前市场上出现了非常多的 nosql 数据库,都可用作缓存数据库,有时候,这些缓存数据库也提供持久化的能力。

小明家的生活条件,在经过爸爸的不懈努力之后,生活水平渐渐提高了;有一天,爸爸对小明说:明仔吖,咱们家现在生活水平提高了,但是爸爸也越来越忙了,这样,如果我忙的时候,你问妈妈或者爷爷奶奶,也是可以拿到生活费的,咱们家这几位长辈手里都有钱了,这就是分布式缓存。

但是分布式缓存又分为主从模式和集群模式,上面说的是集群模式,爸爸妈妈爷爷奶奶都可以拿钱,但是主从模式就不同了,主从模式就是钱都在爸爸手里,爸爸会把钱分给每个长辈一份,如果当时正好爸爸太忙了,没来得及分给妈妈,而小明又恰好问妈妈要生活费的话;妈妈只能对他说:小命呀,不好意思,妈妈这里也没有,你看看再问问其它人(客户端自己轮询),在问了妈妈、爷爷后(引用指向),终于知道,钱在爸爸那里,还得问爸爸要生活费。而且爸爸给其它人分钱的时候,还要占用他工作的时间。

缓存雪崩就是在某一个时刻,大量的缓存同时失效,造成数据库访问压力倍增。小明的爸爸最近压力比较大,因为收入减少了,他爸爸做的一个工程因为种种原因,货款只能分期付清,为了防止小明和妹妹同时申请生活费,造成资金周转困难;爸爸规定妹妹 1 号领取生活费,而小明在 5 号才能领取,小明心里的苦啊!

缓存穿透就是客户端总是尝试访问某个不存在的缓存,造成了每次都要取请求数据库读取数据。就好像小明吧,本来生活挺平静的,这刚上大二,就交了个女朋友,每个月的 1000 元生活费有点捉襟见肘,然后他又不能让爸爸知道,就在申请生活费的时候,每次都多要一点;这样就搞得爸爸很被动,本来计划得好好的,每个月都是 1000 块,这没次都不够,老是要跑银行取现金,终于在3个月后,爸爸发现了这个问题,想着儿子也大了,为了早日抱上孙子,就提高了小明的生活费,解决了每次都要跑银行的问题。

缓存击穿和缓存雪崩有点类似,其中不同的是;缓存雪崩是大量缓存 key 同时过期,而缓存击穿是大量的请求指向同一个缓存key,在这个 key 过期的时候,大量的请求涌入数据库中,造成了瞬间巨大的压力。举个栗子,因为小明交了女朋友的原因,他的生活费总是很快用完了;这种情况下,他也必须在 1 号的时候拿到生活费,不然就要吃土了,但是妈妈不允许他们一起取打扰爸爸,妈妈就指定了妹妹去问,在妹妹没有回来之前,小明只能等着,这就是为了解决缓存击穿而采用的策略:互斥锁(mutex key)

运维级别缓存

除了在应用程序中可以接入缓存以外,部分运维工具也集成了缓存服务,比如 Nginx、IIS。

Nginx 就是反向代理缓存,通过配置 Nginx 的缓存功能,在客户端请求到来到时候去加载缓存内容,用以提高响应能力,IIS 缓存又分为用户缓存和内核缓存。IIS 的输出缓存设置中,内核模式缓存不会对验证等用户信息进行检查,就好像小明等爸爸因为太赶时间,把钱放门卫大妈那里了,结果随便来了个学生就把小明等生活费给领走了,但是加上用户模式缓存后,就可以添加对身份的检查(请求标头),这样大妈就会知道谁是小明而不会随便把生活费交给别人了。

网页静态化

这种技术,在 Web1.0 时代非常的流行,我还记得那些个年头的网站开发项目中的要求,大部分项目的需求分析文档里面就明晃晃的写着:网页静态化!,而静态化常见于各种企业型、论坛帖子,在发表这些信息后就将其生成静态网页,客户端访问的时候,直接重定向到该静态网页,基本无需访问数据库。

CDN 缓存

CDN 缓存类似于上面提到的分布式缓存,但是实际上 CDN 缓存服务目前来说,主要说针对静态资源的,比如图片、视频、文件等等;大家经常可以看到,很多站点都号称提供了 CDN 加速服务,这些站点就像一个个代办信用卡的销售中介,实际上拿的都是银行的资源。

更形象一些的说法,就是大家的钱都是中国人民银行发行的,我们可以通过各个不同的银行(CDN节点)查询我们的银行卡余额(我怎么可能有余额),在以前没有手机银行的时候,大家就可以到附近的银行去查询,然后取款(CDN缓存),如果附近的银行的柜员机没有现金,那么可能就需要到总行去取了(回源),如果发生了太多回源的事件,就会造成 CDN 的拥堵,所以 CDN 服务商也不敢打包票自己的基础服务没有问题,反正我是没见到哪家 CDN 服务商敢注明服务稳定性 100%,基本上都是 99.99%

缓存的理论知识,其实是非常宏大的,我这里只是抛砖引玉,希望能给入门的朋友带来一点帮助,如果你喜欢这篇文章,请给我点赞,让更多同学可以看到。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK