Web缓存是可以自动保存常见文档副本的HTTP设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档。
使用缓存的优点:
- 缓存减少了冗余的数据传输,节省了你的网络费用。
- 缓存缓解了网络瓶颈的问题。不需要更多的带宽就能够更快地加载页面。
- 缓存降低了对原始服务器的要求。服务器可以更快地响应,避免过载的出现。
- 缓存降低了距离的时延,因为从较远的地方加载页面会更慢一些。
1. 缓存命中和未命中的
可以用已有的副本为某些到达缓存的请求提供服务。称为缓存命中(cache hit);
其他一些到达缓存的请求可能会由于没有副本可用,而被转发给原始服务器。称为缓存未命中(cache miss)。
1.1 缓存再验证
原始服务器的内容可能会发生变化,缓存要时不时对其进行检测,看看它们保存的副本是否仍是服务器上最新的副本。这些新鲜度检测被称为HTTP再验证。
缓存再验证时,发现内容无变化,服务器会返回304 Not Modified进行响应。
如果缓存验证副本仍然是有效的,就会再次将副本标识为暂时新鲜的,并将副本提供给客户端,这被称为再验证命中或缓慢命中。
2 命中率
命中率分为文档命中率和字节命中率。
文档命率说明阻止了多少通往外部网络的Web事务。事务有一个通常都很大的固定时间成分(TCP连接)提高文档命中率对降低整体延迟很有好处。字节命中率说明阻止了多少字节传向因特网。提高字节命中率对节省带宽有利。
2.1 区分命中和未命中的情况
客户端有一种方法判断响应是否来自缓存,使用Date首部。将响应中Date首部的值与当前时间进行比较,如果响应中的日期时间比较早,客户端通常就可以认为这是一条缓存的响应。客户端也可以通过Age首部来检测缓存的响应,通过这个首部可以分辨出这条响应的使用期。
3 缓存的拓扑结构
专用缓存被称为私有缓存。
共享的存被称为公有缓存。
3.1 私有缓存
Web浏览器中有内建的私有缓存——大多数浏览器都会将常用文档缓存在你个人电脑的磁盘和内存中,并且允许用户去配置缓存的大小和各种设备。
3.2 公有代理缓存
公有缓存是特殊的共享代理服务器,被称为缓存代理服务器(caching proxy server),或者更常见地被称为代理缓存(proxy cache)。
3.3 代理缓存的层次结构
两级缓存的层次结构,其基本思想是在靠近客户端的地方使用小型廉价缓存,更高层次中,逐步采用更大、功能更强的缓存来装载多用户共享的文档。
3.4 网状缓存、内容路由以及对等缓存
有些网络结构会构建复杂的网状缓存(cache mesh),而不是简单的缓存层次结构。网状缓存中的代理缓存之间会以更加复杂的方式进行对话,做出动态的缓存通信决策,决定与哪个父缓存进行对话,或者决定彻底绕开缓存,直接连接原始服务器。这种代理缓存会决定选择何种路由对内容进行访问、管理和传送,称其为内容路由。
网状缓存中为内容路由设计的缓存的功能:
- 根据URL在父缓存或原始服务器之间进行动态选择。
- 根据URL动态地选择一个特定的父缓存。
- 前往父缓存之前,在本地缓存中搜索已缓存的副本。
- 允许其他缓存对其缓存的部分内容进行访问,但不允许因特网流量通过它们的缓存。
3.4.1 兄弟缓存(sibling cache)
缓存之间这些更为复杂的关系允许不同的组织互为对等(peer)实体,将它们的缓存连接起来以实现共赢。提供可选的对等支持的缓存被称为兄弟缓存。
HTTP并不支持兄弟缓存,所以人们通过一些协议对HTTP进行了扩展,比如因特网协议(Internet Cache Protocol,ICP)和超文本缓存协议(HyperText Caching Protocol,HTCP)。
4 缓存的处理步骤
- 接收——缓存从网络中读取抵达的请求报文。
- 解析——缓存对报文进行解析,提取出URL和各种首部。
- 查询——缓存查看是否有本地副本可用,如果没有,就获取一份副本(并将其保存在本地)。
- 新鲜度检测——缓存查看已缓存副本是否足够新鲜,如果不是,就询问服务器是否有任何更新。
- 创建响应——缓存会用新的首部和已缓存的主体来构建一条响应报文。
- 发送——缓存通过网络将响应发回给客户端。
- 日志——缓存可选地创建一个日志文件条目来描述这个事务。
注意点:
缓存不应该调整Date首部。Date首部表示的是原始服务器最初产生这个对象的日期。
4.1 缓存处理流程图
5 保持副本的新鲜
- 文档过期
- 服务器再验证
5.1 过期响应首部
首部 | 描述 |
---|---|
Cache-Control:max-age | max-age值定义了文档的最大使用期——从第一次生成文档到文档不再新鲜、无法使用为止,最大的合法生存时间(以秒为单位)Cache-Control:max-age=484200 |
Expire | 指定一个绝对的过期日期。如果日期已经过了,就说明文档不再新鲜了,Expire:Fri,05 Jul 2002,05:00:00 GMT |
5.2 服务器再验证
- 如果在验证显示内容发生了变化,缓存会获取一份新的文档副本,并将其缓存再旧文档的位置上,然后将文档发送给客户端。
- 如果再验证显示内容没有发生变化,缓存只需获取新的首部,包括一个新的过期日期,并对缓存中的首部进行更新就行了。
HTTP协议要求行为正确的缓存返回下列内容之一:
- “足够新鲜”的已缓存副本;
- 与服务器进行过再验证,确认其仍然新鲜的已缓存副本;
- 如果需要与之进行在验证的原始服务器出故障了,就返回一条错误报文;
- 附有警告信息说明内容可能不正确的已缓存副本。
5.2.1 缓存再验证中使用的两个条件首部
首部 | 描述 |
---|---|
If-Modified-Since: | 如果从指定日期之后文档被修改过了,就执行请求的方法。可以与Last-Modified服务器响应首部配合使用,只有在内容被修改后与已缓存版本有所不同的时候才去获取内容 |
if-None-Match | 服务器可以为文档提供特殊的标签,而不是将其与最近修改日期相匹配,这些标签就像序列号一样。如果已缓存标签与服务器文档中的标签有所不同,If-None-Match首部就会执行所请求的方法 |
5.2.2 实体标签
使用场景:
- 有些文档可能会被周期性地重写,但实际包含的数据常常是一样的。尽管内容没有变化,但修改日期会发生变化。
- 有些文档可能被修改了,但所做修改并不重要,不需要让世界范围内的缓存都重装数据。
- 有些服务器无法准确地判定其页面的最后修改日期。
- 有些服务提供的文档会在亚秒间隙发生变化,对这些服务器来说,以秒为颗粒的修改日期可能就不够用了。
5 控制缓存的能力
首部 | 解释 | 优先级 |
---|---|---|
Cache-Control:no-store | 防止缓存提供未经证实的已缓存对象 | ⬇️ |
Cache-Control:no-cache | 防止缓存提供未经证实的已缓存对象,标识为no-cache的响应实际上是可以存储在本地缓存区中的。只是在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用 | ⬇️ |
Cache-Control:must-revalidate | 告诉缓存,在没有跟原始服务器进行再验证的请况下,不能提供这个对象的陈旧副本。缓存仍然可以随意提供新鲜的副本。如在缓存进行must-revalidate新鲜度检查时,原始服务器不可用,缓存就必须返回一条504Gateway Timeout错误 | ⬇️ |
Cache-Control:max-age | 首部表示从服务器将文档传来之时起,可以认为此文档处于新鲜状态的秒数。s-maxage仅适用于共享(公有)缓存。max-age=0表示每次访问的时候都进行刷新 | ⬇️ |
Expire | 指的是实际的过期日期,不推荐使用 | ⬇️ |
5.1 客户端的新鲜限制
Web浏览器都有Refresh(刷新)或Reload(重载)按钮,可以强制对浏览器或代理缓存中可能过期的内容进行刷新。Refresh按钮会发布一个附加了Cache-Control请求首部的GET请求,这个请求会强制进行再验证,或者无条件地从服务器获取文档。
指令 | 目的 |
---|---|
Cache-Control:max-stale Cache-Control:max-stale= | 缓存可以随意提供过期的文件。如果指定了参数 |
Cache-Control:min-fresh=s | 至少在未来s秒内文档要保持新鲜。这就使缓存规则更加严格了 |
Cache-Control:max-age=s | 缓存无法返回时间长于s秒的文档。这条指令会使缓存规则更加严格,除非同时还发送了max-stale指令,在这种情况下,使用期可能会超过其过期时间 |
Cache-Control:no-cache Pragma:no-cache | 除非资源进行了再验证,否则这个客户端不会接受已缓存的资源 |
Cache-Control:no-store | 缓存应该尽快从存储器中删除文档的所有痕迹,因为其中可能会包含敏感信息 |
Cache-Control:only-if-cached | 只有当缓存中有副本存在时,客户端才会获取一份副本 |