为了减少网络延迟以及降低服务器压力,web 开发中用了大量的缓存机制。 缓存的目的就是把需要花费昂贵开销的计算结果保存起来,在以后需要的时候直接取出,进而避免重复计算。
web 缓存有以下几种:
- 客户端缓存
- 代理服务器缓存
- CDN 缓存
- 数据库查询缓存
- 应用计算缓存
客户端缓存
客户端(浏览器)缓存机制,其实主要就是 HTTP 协议定义的缓存机制, 通过以下 HTTP 协议头字段来控制 html 页面缓存:
规则 | 消息头 | 值 | 类型 | 作用 |
---|---|---|---|---|
新鲜度 | Expires | Sun, 16 Oct 2016 05:43:02 GMT | 响应 | 告诉浏览器在过期时间前可以使用副本(有可能存在时间不一致问题) |
Pragma | no-cache | 响应 | 告诉浏览器忽略资源的缓存副本 | |
Cache-Control | no-cache | 响应 | 告诉浏览器忽略资源的缓存副本,强制每次请求直接发送给源服务器 | |
no-store | 响应 | 强制缓存在任何情况下都不要保留任何副本 | ||
max-age=[秒] | 响应 | 指明缓存副本的有效时长,从请求时间开始到过期时间之间的秒数 | ||
public | 响应 | 任何途径的缓存者(本地缓存、代理服务器),可以无条件的缓存该资源 | ||
private | 响应 | 只针对单个用户或实体(不同用户、窗口)缓存资源 | ||
Last-Modified | Sun, 16 Oct 2016 05:43:02 GMT | 响应 | 告诉浏览器当前资源的最后修改时间 | |
If-Modified-Since | Sun, 16 Oct 2016 05:43:02 GMT | 请求 | 如果浏览器第一次请求时响应中 Last-Modified 非空,第二次请求同一资源时,会把它作为该项的值发给服务器 | |
校验值 | ETag | 50b1c1d4f775c61:df3 | 请求 | 告知浏览器当前资源在服务器的唯一标识符(生成规则由服务器决定) |
If-None-Match | 50b1c1d4f775c61:df3 | 请求 | 如果浏览器第一次请求时响应中 ETag 非空,第二次请求同一资源时,会把它作为该项发给服务器 | |
辅助 | Vary | Accept-Encoding | 响应 | 辅助从多个缓存副本中筛选合适的版本(不同压缩算法产生的副本) |
其中 Cache-Control
的缓存控制方式比较多,如下图:
客户端和服务端对这些 HTTP 协议头字段的处理如下图:
用户在使用浏览器时各种操作对缓存的影响如下:
用户操作 | Expires/Cache-Control | Last-Modified/Etag |
---|---|---|
地址栏回车 | 有效 | 有效 |
页面链接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进、后退 | 有效 | 有效 |
F5 刷新 | 无效 | 有效 |
Ctrl+F5 刷新 | 无效 | 无效 |
代理服务器缓存
Web 代理服务器使用与客户端同样的缓存原理,只是规模更大。 代理服务器群为成百上千用户服务使用同样的机制, 大公司和 ISP 经常在他们的防火墙上架设代理缓存或者单独的缓存设备。
由于代理服务器缓存并非客户端或者源服务器的一部分,而是位于原网络之外,请求必须路由到它们才能起作用。
- 手工设置你的浏览器:告诉浏览器使用哪个代理
- 通过中间服务器:用户不必配置代理,所有的 web 请求均发送到中间服务器,其后将请求转发到后台网络
代理服务器缓存是一个共享缓存,不只为一个用户服务,经常为大量用户使用,因此在减少相应时间和带宽使用方面很有效。
CDN 缓存
由于网络通信的传播速度是存在物理极限的, 既然不能改变传播速度,那我们就可以缩短用户与服务的距离, 于是就引入了 CDN(Content Delivery Network,内容分发网络)。
CDN 缓存属于 Cache 服务器的一种, 其目的是通过在现有的 Internet 中增加一层新的网络架构, 将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容, 从而解决 Internet 网络拥塞状况,提高用户访问网站的响应速度。
数据库查询缓存
大多服务端的性能瓶颈是数据库查询,因为应用关系较复杂,数据表格繁多,频繁进行数据库查询又涉及到大量的磁盘 IO 和计算, 所以服务端引入了专门的缓存服务(redis、memcached 或应用自建缓存服务)以保存查询结果, 以便于下次查询时,直接从内存缓存直接返回,提供响应效率。
应用计算缓存
有些 Web 应用会有一些大量的 CPU 密集型的计算,这些计算结果也有可能保存在缓存服务内以便后用。
这些应用计算不仅可以在服务端,而且可以在客户端。
服务端缓存服务大多由 redis 或 memcached 提供,而客户端缓存服务可以由浏览器的 LocalStorage 或 SessionStorage API 提供。