00:00
嗯,哈喽,同学们好,我们刚刚给大家讲完了资源静态化这一部分内容,那么我们就顺着这个资源静态化呢,接下来给大家来聊比较大的一块内容就是缓存,其实资源静态化呢,就相当于把我们后端应用服务器里边这些动态的资源呢,呃,把它给生成成了静态资源,相当于是呃,我们上游服务器里边的这些动态请求做出了一层呃缓存的些操作,把这个本应动态查询的这些操作呢前置化了。在做缓存的时候呢,有一个最根本的原则,就是把这个缓存的内容和数据尽可能的向我们的用户去贴近,我们看一下这张图。呃,在这张图里呢,我们画了呃相对来说比较复杂的一个系统架构图,它从用户接入互联网开始,呃,一直到我们的这个后端计算的应用服务器,我们上节课给大家讲的这个资源静态缓存呢,其实就属于我们在呃后端服务器里边把内容生成成静态页面,放置到了我们的NG格里,这也相当于一层缓存,那么我们在这给大家讲的是多级缓存,那除了这个资源静态化的缓存之外,还有很多其他的缓存,比如说第一个呢,这个浏览器缓存。
01:16
那用户在请求我们的资源的时候,其实没有必要啊,让用户把每一次请求全部都打向我的服务器,我们可以通过浏览器看到这个,其实有很多的请求并没有真正发送到服务器端,而是利用了浏览器本机或者是本地的这个一些之前访问过的记录的存储来直接响应我们的用户了。那我们通过NG啊,其实也是可以控制这个浏览器究竟对哪些文件,哪些请求去做缓存,哪些请求不去做缓存。那之前也跟大家说过,那解决高并发的最好的办法呢,就是让它不产生高并发,对吧,其实这种这个做法呢,在现在主流的很多这个APP上,网站上的也都有应用,比如说在双11的淘宝的这种抢购上啊,很多情况下,其实是你根本就没有机会把这个呃请求发送给这个服务器端,而直接给你展示了一下这个,呃,当前的这个库存就已经没有了。
02:14
对吧,而不是把这个请求直接呃发送给后端的服务器,让他去校验一下我究竟库存数得不得,能不能得到现在的满足,他在这个客户端这儿呢,就已经做好了一层限制,但这种限制呢,并不是说不让他直接访问啊,有很多的这个提前预,这个预埋或者提前下发的数据,有很多种方法可以让我们的这个呃用户不发送这种请求。给大家举一个简单的例子,比如在双11上,我们针对某一个商品,呃,然后再去做秒杀的时候,那用户,呃,如果要是全网的这些用户的所有的请求,在发送到这个服务器的过程当中,我们经历一次计算。啊,也就是说,呃。这次计算呢,我可以。
03:01
呃,让我们这个客户端能自己算一下自己,他能不能够把这个请求发送给服务器,呃,举一个简单的例子吧,比如说呃,我们这发送请求的时候,呃,服务器端呢,提前下发了一部分的这个预埋的数据。呃,可以得知呢,当前这个商品或者某一个热门商品,那它的库存量呢,可能就只有100个,或者是呃,几十个。那当前的这个并发的请求,呃,可能会比较多,当当这个当前这个请求比较多的时候,我们的这个客户端呢,可以从另外一个通道可以感知到当前的热门商品是啥啊,这里边呢,主要分两步操作,首先第一呢是显示,就是在做秒杀的时候,它会先展示这个当前的这个,呃,这个页面,那我们的用户呢,会不断的刷新到一个时间点的时候。然后才会显示这个可以购买的按钮,在这个正经的这个可以点的这个按钮出现之前呢,它应该出现是即将开始对吧?呃,在刷新页面的过程当中呢,这即将开始,它会变成这个立即抢购。
04:13
那么我们在这刷新的过程当中,服务器端,我们的这个后端服务器啊,就已经可以得知用户在刷新哪些商品了,就是这个过程呢,就可以收集呃,当前有哪些真正的这个热门的商品,那么针对当前热门商品呢,我们就可以在。呃。后台或者是这个背后的这个线程里边,在下发给我们的客户端另外一份数据就是当前热门商品的列表,那我们客户端呢,就知道当前有哪些呃商品呢,是比较热门不容易抢购的了,比如说都已经达到了1万:1了,那这会儿其实我们就没有必要让所有的用户啊都去点击这个按钮啊,这里边也有很多种方式,比如说压根儿就到点之后呢,直接把这个立即抢购呢,就变成了另外一种状态,就是这个是什么,你来晚了就已经没有库存了啊,通过客户端的逻辑判断就可以屏蔽掉用户去点击这个按钮,那另外一方面就是即使他点击这个按钮,也可以让在让他在这个呃后端服务器这呢,直接把它屏蔽掉,而不是直接把呃这个。
05:25
添加购物车,或者是这个检查库存的请求,真正发送到后端服务器,由NGS这一层呢,就可以把它给拦截住,也是通过这个,呃,一些热点数据的判断,直接给他展示一下在页面上啊,就让他及时点了这个立即抢购按钮,也可以让他返回。这个您来晚了,这个页面这是屏蔽掉客户端的一些请求,在这儿只是举一个简单的例子,现在很多电商平台呢,依旧使用的是这种方法,只是它实现的逻辑啊,会比这个更复杂一些啊。那么我们的这样呢,就可以屏蔽掉很多客户端,发送真正的这些呃请求打到我们的服务器上,从而呢来处理高并发。
06:07
那么,呃。除了这种屏蔽用户请求之外,那通常还有一种呃,比较比较比较合理或者比较正常的方法,就是刚才跟大家说的,在浏览器这一端呢,去做一些缓存,或者是在客户端做缓存。这个如果说客户端的话呢,就既包含了浏览器,还包含了APP啊,咱们现在呢,就只呃单指这个浏览器这种应用,因为APP的这种开发呢,就是基于CS端的啊,这两端开发,也就是说我们不只是需要开发这个服务器端这些应用,对于客户端呢,有很多这种逻辑上的判断,你像这种呃,有一些内嵌的逻辑,那在浏览器里边是完成,这他是没法完成的。啊,浏览器呢,毕竟有它自身的这种局限性啊,它出于安全性的考虑也好,或者是功能性的限制也好,它是没法做到像客户端这么灵活的,那我们在这讲这个客户端的缓存呢,在这儿就讲这个HTTP协议下的浏览器的缓存,浏览器可以通过控制本机上的这个存储空间来去缓存,缓存一下之前访问过的这些历史记录。
07:10
啊,但是他没法做到特别灵活,比如说预埋一些数据啊,我到什么时候可以访问哪些这个,这个我已已经这个缓存下来的这个资源,所谓的预埋就是提前下发嘛,比如访问了一下这个页面,然后呢,下载下来一部分数据存在浏览器客户端了,那等到这个呃,11点左右的时候,我才可以用这个,呃,或者说这个,或者说我再去用这本机存储的这个,呃,这些页面这是做不到的,起码的浏览器这一端现在是做不到的。在浏览器呢,这边呢,我可以缓存用户的数据,然后呢,避免发送请求,比如一个页面里边有很多请求,CSSJS,那这些压根就经常不变的东西,或者变化很少的东西,那就不让他再去呃发送这些请求了啊,浏览器呢也省心,然后服务器端呢压力也变小了。啊,这是呃,基于浏览器这一层的缓存。
08:01
然后再有一层呢,就是基于CDN的缓存。CDN呢又从全网内容分发络啊,就是这一块内容啊,我们可以通过设置或者配置一个上游的呃服务器,这个上游服务器单指对的是这个CDN的这个呃集群,那么它可以呃把内容呢分发到所有的CDN的这些机器上,就像我们上节课呃给大家讲的这个。呃,我们有一台云的这个主机,在上面的去生成静态的HTML页面,然后呢,把它再给分发到,呃这个全网其他的这些节点上,只是这个区别就在于我们上节课讲的是在内网集群里边去做分发啊,那这个呢,它是在全网分发,也就是他已经不在单一的一个机房里了,甚至已经跨了跨,跨了区域,甚至跨了国家。那可以在呃。全球的这些热门城市,我们去部署自己的服务器,然后把一份内容呢,同时分发到这些这个服务器上,在用户访问的时候呢,就可以通过这个解析用户当前所在地址的呃IP,然后呢去就近让他去访问呃这个缓存还有另外一层原则呃,就是把呃内容和用户呃。
09:17
距离拉近,距离越近,访问速度呢,它也就越快,那这种内容内容的这种全网分发,一般来说啊,它比较适合静态资源分发,或者说不是经常变化的这种资源分发,但是现在也有很多CDN的内容,内容提供商可以呃提供这种动态内容的缓存了啊也是比如说我们在这个一个列列表页里边,我们需要翻页,第一页,第二页,第三页,那这肯定是动态的内容,对吧,那这种动态的内容。你得要缓存下来了,呃,分发到这些节点上,那用户在请求的时候呢,肯定不是及时的这个数据。但是如果要是你的这个呃,分页列表页呃,可能需求上来讲啊,就并不是特别需要特别强这种一致性,或者是及时性并不高。
10:06
比如说有一些新闻,比如说有一些这个呃内容,它可以在比如说呃一分钟或者或者三五分钟之内,呃同步到全这个全球的节点上,它也是能接受的,那么你就可以这个这么去做,因为像一些内容需要审核这些呃操作这种内容分这个在在在真正的这个展示给用户之。这个之间啊,需要经历,本身它就需要经历一段时间,那我们就可以在利用这段时间审核完之后呢,再去把它给分发到全网,然后批量去更新一下,一般来说缓存啊,也不会把啊,像这种列表页,这种分页这种方式,他也不会把从第一页到到第一到第1万页,每一页的内容全部都缓存了啊,基本上也就是缓存前十页,大伙儿比较频繁爱点这种,包括百度啊,我们在搜索一些东西的时候。呃,搜索出来的内容呢,这肯定不是最新最及时的内容,那也是在百度的这个服务器里边,提前就已经存储好的数据,他需要把最新内容扒回来,更新那份数据,然后我们才能搜到最新的内容,与此同时呢,像百度搜索这种,还有谷歌搜索,它的前边的这几页都是需耗时非常非常短的,不信大家可以自己去看一下,那么对于一些热门关键字,它的前边这几页,我们就可以把它给缓存下来,然后在一段时间内呢去给它更新,这也是这种全网静态资源分发,我们可以使用的场景,除了静态的纯纯粹静态资源之外啊,有有这种动态请求呢,也是可以这个给它给缓存一下的。
11:40
那么我们在构建大型网站的时候呢,前面给大家给大家讲这两层缓存,一个是基于我们本机的静态缓存和这个全网的CDN的缓存,已经能够应付大部分的这种场景了,可以屏蔽掉很多客户端的这种,呃,这种重复性的请求啊,没有意义的请求呢,就不要让他打到我的服务器端了,大部分的请求呢,在这块呢,就已经给过滤掉了。
12:05
然后剩下呢,还有很多点求,它需要向我们的这个N这个服务器发起,那么在N这个这一层里边,我们也可以做缓存,在这里边呢可以做。呃。基于这个本机的这个pro catch的缓存,也就是基于反向代理或者说叫正向代理的缓存,在N在做代理服务器的时候,它是需要向他的上游服务器去发起请求的,那把请求拉回到本机,如果要是相同的请求的话。那我是不是可以把它的请求呢,从上游服务器拉回来,在本地上存储一份,如果要是相同的请求就不再去。向这个上游服务器发起相同的请求了啊,从而去,嗯。控制,呃。后端或者叫上游服务器这个并发量啊,把请求拦截到NG上,NG的性能呢,本身是非常非常高的,尤其是对于处理静态资源。啊,但是这个上游服务器这个计算效率并不取决于这个NGNG即使性能再高,它也只是把请求转发过去了。
13:09
这边如果要真正做一些复杂的计算的话,那么在拉回来的时候呢。这个请求呢,呃也是需要这个呃后上游服务器去做计算的,跟N本质上的无关,那么在N这一层,如果你有一些频繁或者热点的这些呃数据的请求,即使动态请求呢,我们也可以把它给缓存起来,比如说呃,当前呢,比如说某一个呃。某一个明星吧,他比较呃火热,呃,出现了什么事件吧。我们在这比如说查询user ID等于100。呃,举个例子吧,比如说呃,Account。嗯,点问号UID等于100。那这会儿出现了极为频繁的数据,在这个N上去做反向代理,那他需要反向代理到上游服务器,每次都得由上游服务器去查询,然后再返回,那NG就可以针对当前这个URL啊,这完整的URL去做一次缓存,把它返回的HTML数据直接存在NG上,那下次再请求的时候呢,我直接把本机这本机的这个之前请求过的HTML直接反馈我们用户了啊,那有有同学可能在这会想这个时效性的问题,对吧,比如他展示了一些明星的。
14:29
一些呃动态啊,一些个人信息啊,一旦他要发生变化了,我们这边怎么去做更新,那这是另外一个话题,我们再仔细讲的时候啊,咱们再慢慢再去学啊,这是NG这一层在做代理服务器的时候,正向代理或者反向代理在这一层呢,都可以去做缓存啊,再有就是这种缓存呢,主要是基于磁盘文件性质的存储。磁盘文件呢,呃,在性能上呢,略略低于这个内存啊,如果要是有一些比较典型的场景,能达到成百上千那种差距,所以在NG上面,针对这种极为热点的这种请求呢,我们甚至都可以把请求的内容呢缓存到内存里,这就是内存级别的,呃,NG在NG这里边呢,做内存级别的缓存,那响应速度要远远高于这个磁盘的缓存。
15:20
啊,而且磁盘缓存和这个内存池的缓存,我们可以把它给区分开来配合使用,而不是只选其一,因为磁盘空间呢,它比较大是吧,然后这个内存空间呢,一般来说都比较,呃,受受受到限制,即使现在的服务器你动不动就64128G的内存。这当然是没有问题,但它远远没有硬盘来的更加廉价和低和低廉,所以在分层的时候呢,可以把价值略低一些的这个数据呢,我们把它放到磁盘上,或者访问频次啊,我们在做预估的时候,某一些这个模块,某一些功能的在这儿做缓存,然后另外一些极为热点的内容呢,在内存里做缓存,比如说秒杀,或者说这个秒杀显示当前的这一些,呃,热点商品的这个,呃。
16:10
详这个详情页啊,它的这个分类,它的这种它的这种这个一些,呃,额外的一些所需要的一些资源,我全部都把它给放在内存里,然后非热点商品呢,就把它放到这个磁盘上啊,给它给分开。然后除了这个N这内存的这种缓存之外呢,啊,我们当然还可以去配置上游服务器的缓存啊,那这个呢,其实也就不在我们N这这套课程里边这个授课范围之内了啊,这种方案呢,也是非常完善,而且这个极为复杂庞大的,在我们的上游服务器里,不管你是上游服务器是PHP的还是Java的也好,对吧,他们一般来说呢,在自己的本机上的都可以做缓存,另外就是在这个呃,第三方第三方的这个节点上,比如说red或者memory catch啊去做缓存,当然N呢,也是可以利用memory memory catch或者red去做第三方缓存的,也就是它自身的这个缓存,第一呢是不好控制,第二呢就是需要扩展啊,然后我们就可以通过NG去连接到这个,呃,Memory CA或者或者是N几把本应该存在N内部的这个。
17:18
内存空间的这些这份内容呢,给他给。存放到这个第三方服务器上啊。呃,这是多级缓存啊,缓存呢,不能只设置这么一块内容啊,它是不满足我们复杂这种应用场景的,在这儿呢,给大家先介绍一下这个多级缓存它的应用场景,总的来说呢,我们的原则就是让数据呃,尽可能去靠近用户,第二方面就是让用户的请求呢,尽量的去减少,真正的真正的这个请求到我们的这个最复杂的这个服务器上。啊,用户的请求越少,我们能需要处理的东西也就越少,那么并发量呢,随之呢,呃也就把它给呃减少了,所谓的这个削风啊,其实就是把峰值的一些请求呢给它给平,这个把它给平摊了,平摊到了更多的这种节点上,本来我们这些请求全都要打到NG上,那通过多级学风呢,到真正到NG上之后呢,请求量呢,其实就已经不多了,那透过NG再去向我们的这个呃上游服务器上去访问真正的数据的话,那这会儿的真正的请求呢,就是少之更少了。
18:28
那我们这会儿再去应对高并发的话,就会显得更加的游刃有余,更加的有信心了啊,那这就是我们给大家先介绍一下这个多级缓存,那接下来呢,我们会分这些方向,然后逐一去击破啊。把这个呃缓存学好了啊,我们就可以去做一些这种大型网站的技术架构了,如果有机会的话就可以,呃,其实你看我对NG呢,了解的算比较多,那主要就是因为之前呢,游走各个公司里边做了好多这种真正的实践。
19:01
把这些东西呢,扔到这个。真正的线上线上的环境去跑一跑,这会儿你可能会发现所谓的高并发呢,并没有呃想象想象中那么恐怖,只要你手里的这个武器足够的话,你就可以层层去削弱它的这个身上的护甲,然后最后再去呃,面临它的冲击的时候呢,就显显得不堪一击了,然后再有就是这个呃。你接触这个N的这个。这种功能啊,模块或者解决方案比较多的时候,在你的这个系统当中,呃,一旦出现了一些瓶颈的时候,你也比较好解决,你手里的武器也会更多啊,再有就是呃,NG格本来它是一个运维需要学的东西,呃在咱们的这个。Java程序员,或者是这个其他的这个后端开发者,你把它你把它学明白之后啊,其实是可以向整体的系统设计更迈迈进一步的,因为它处理的就是用户的流量,你能看到了整个用户流量的走向,而不像一个普通程序员只是做一个单一的模啊,那这样的话,呃,去了一些这个公司,那么你在。
20:12
去处理他们的一些新的请求的时候,就可以去套用你之前所实施过的这种方案了啊,这是多级缓存,那么接下来呢,一步一步的给大家来介绍和学习这个,呃,N基于N这些缓存究竟应该怎么去使用和配置,以及有一些的有一些这个额外的注意事项啊。
我来说两句