网络缓存的三个层次

学习自:深入分布式缓存

不涉及操作系统和硬件的缓存,根据在软件系统中所处位置的不同,缓存大体可以分为三类:
❑ 客户端缓存;
❑ 服务端缓存;
❑ 网络中的缓存。

缓存是系统调优时常用且行之有效的手段

主流的缓存算法

(1)Least-Recently-Used(LRU)
替换掉最近被请求最少的对象,这种传统策略在实际中应用最广。在CPU缓存淘汰和虚拟内存系统中效果很好。然而在直接应用与代理缓存中效果欠佳,因为Web访问的时间局部性常常变化很大。
浏览器就一般使用了LRU作为缓存算法。新的对象会被放在缓存的顶部,当缓存达到了容量极限,底部的对象被去除,方法就是把最新被访问的缓存对象放到缓存池的顶部。

(2)Least-Frequently-Used(LFU)
替换掉访问次数最少的缓存,这一策略意图是保留最常用的、最流行的对象,替换掉很少使用的那些数据。然而,有的文档可能有很高的使用频率,但之后再也不会用到。传统的LFU策略没有提供任何移除这类文件的机制,因此会导致“缓存污染”,即一个先前流行的缓存对象会在缓存中驻留很长时间,这样,就阻碍了新进来可能会流行的对象对它的替代。

客户端缓存

页面缓存

页面缓存是将之前渲染的页面保存为文件,当用户再次访问时可以避开网络连接,从而减少负载,提升性能和用户体验。随着单页面应用(Single Page Application, SPA)的广泛使用,加之HTML5支持了离线缓存和本地存储,大部分BS应用的页面缓存都可以举重若轻了。

之前的笔记

1)当浏览器访问了一个包含manifest属性的页面时,如果应用的缓存不存在,浏览器会加载文档,获取所有在清单文件中列出的文件,生成初始缓存。
2)当对该文档再次访问时,浏览器会直接从应用缓存中加载页面以及在清单文件中列出的资源。同时,浏览器还会向window.applicationCache对象发送一个表示检查的事件,以获取清单文件。
3)如果当前缓存的清单副本是最新的,浏览器将向window.applicationCache对象发送一个表示无须更新的事件,从而结束更新过程。如果在服务端修改了任何缓存资源,必须同时修改清单文件,这样浏览器才能知道要重新获取资源。
4)如果清单文件已经改变,那么文件中列出的所有文件会被重新获取并放到一个临时缓存中。对于每个加入到临时缓存中的文件,浏览器会向window.applicationCache对象发送一个表示进行中的事件。
5)一旦所有文件都获取成功,它们会自动移动到真正的离线缓存中,并向window. applicationCache对象发送一个表示已经缓存的事件。鉴于文档早已经从缓存加载到浏览器中,所以更新后的文档不会重新渲染,直到页面重新加载。

浏览器缓存

HTTP相关字段

之前相关笔记

一篇非常详细的解读

如果在浏览器设置缓存,通常有两个主要作用。
•对用户来说,减少请求可以更快地加载页面,节省流量
•对网站来说,减少带宽压力和费用。

对于浏览器来说,如何缓存一个资源是服务器端制定的策略,自己只是根据服务器的“指令”来执行而已
服务器通过对每个资源的HTTP响应头设置属性和值,来发出自己的缓存指令。

HTTP1.0提供了一些很基本的缓存特性,例如在服务器侧设置Expires跟Last-Modified的HTTP头

HTTP 1.1有了较大的增强,缓存系统被形式化了,引入了实体标签e-tag和属性Cache-Control。e-tag是文件或对象的唯一标识,这意味着可以请求一个资源,以及提供所持有的文件,然后询问服务器这个文件是否有变化。如果某一个文件的e-tag是有效的,那么服务器会生成304-Not Modified应答,并提供正确文件的e-tag,否则,发送200-OK应答。

Last-Modified/ETag与Cache-Control/Expires的作用是不一样的,如果检测到本地的缓存还在有效的时间范围内,浏览器则直接使用本地缓存,不会发送任何请求。两者一起使用时,Cache-Control/Expires的优先级要高于Last-Modified/ETag。即当本地副本根据Cache-Control/Expires发现还在有效期内时,则不会再次发送请求去服务器询问修改时间(Last-Modified)或实体标识(e-tag)了。

Cache-Control与Expires的功能一致,都是指明当前资源的有效期。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。

Expires的值是一个日期,表示某日期之前都不再询问。
Cache-Control的值是:max-age=7776000, max-age的单位是秒,从浏览器接收到文件之后开始计时。

一般情况下,使用Cache-Control/Expires会配合Last-Modified/ETag一起使用,因为即使服务器设置缓存时间,当用户点击“刷新”按钮时,浏览器会忽略缓存继续向服务器发送请求,这时Last-Modified/ETag将能够很好利用服务端的返回码304,从而减少响应开销。

•对于动态生成的HTML页面使用HTTPS头:Cache-Control: no-cache。
•对于静态HTML页面使用HTTPS头:Last-Modified。

强缓存

强缓存:不会向服务器发送请求,直接从缓存中读取资源

通过设置Expires 和 Cache-Control实现

强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容是否已经发生了更新呢?此时我们需要用到协商缓存策略。

协商缓存

强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

通过设置Last-Modified 和 ETag 实现

  • 协商缓存生效,返回304和Not Modified
  • 协商缓存失效,返回200和请求结果

通常会取响应头中的 Date 减去 Last-Modified 值的 10% 作为缓存时间。

我们可以通过查看服务器的log,查看304响应与200响应的比例,来做出一个合理的缓存策略。

缓存位置

从缓存位置上来说分为四种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络。

  • Service Worker
  • Memory Cache
  • Disk Cache
  • Push Cache

是用户在浏览器如何操作时,会触发怎样的缓存策略。主要有 3 种:

打开网页,地址栏输入地址: 查找 disk cache 中是否有匹配。如有则使用;如没有则发送网络请求。

普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache 是可用的,会被优先使用(如果匹配的话)。其次才是 disk cache。

强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control:no-cache(为了兼容,还带了 Pragma:no-cache),服务器直接返回 200 和最新内容。

网络中的缓存

Web代理缓存

正向代理隐藏客户端,反向代理隐藏服务器端,透明代理隐藏代理服务器。

在使用正向代理时,一般需要在浏览器的设置窗口中的“代理服务器”一栏中填写正向代理的IP地址

正向代理多用于中小企业网络环境,Cache设备作为企业网的出口网关提供代理服务、内容缓存、Internet访问控制、安全认证等功能。

反向代理服务器部署与应用服务器部署在同一网络环境中,应用服务器借助反向代理对外提供服务,反向代理提供负载分担和安全隔离作用。

边缘缓存

如果反向代理服务器能够做到和用户来自同一个网络,那么用户访问反向代理服务器,就会得到很高质量的响应速度,所以可以将这样的反向代理缓存称为边缘缓存。

边缘缓存在网络上位于靠近用户的一侧,可以处理来自不同用户的请求,主要用于向用户提供静态的内容,以减少应用服务器的介入。

边缘缓存中典型的商业化服务就是CDN。CDN是Content Delivery Network的简称,即“内容分发网络”

通过HTTP响应头中的Cache-control: max-age的字段来设置CDN边缘节点的数据缓存时间。

一般地,CDN边缘节点对开发者来说是透明的,开发者可以通过CDN服务商提供的“刷新缓存”接口来清理位于CDN边缘节点上的缓存数据。

服务端缓存

简单了解一下一个多级缓存实例

Nginx应用服务器的本地缓存解决了热点数据的缓存问题,Redis分布式缓存集群减少了访问回源率,Tomcat应用集群使用的平台级缓存防止了相关缓存失效/崩溃之后的冲击,数据库缓存提升数据库查询时的效率。正是多级缓存的使用,才能保障系统具备优良的性能。