二.缓存——HTTP权威指南解读系列

441 阅读6分钟

什么是Web缓存?是可以自动保存常见资源副本的设备,处于客户端与服务端之间。当Web请求达到Web缓存时,如果存在资源副本,就从其中而不是从原始服务器中获取该副本。缓存机制存在以下几个显著的优点:

  • 减少冗余的数据传输(服务器多次传输同一份文档)
  • 节约网络带宽,资源加载更快(LAN速度比WAN快)
  • 降低服务器负载压力(突发事件、活动页面网络拥塞)
  • 减少了传输延时(距离过长时光速也会出现延迟)

1)缓存的命中:

缓存功能虽然优点良多,但不能解决所有的问题。其中有两个主要原因是:1.资源太多了,不可能包罗万象地去逐一缓存;2.文档也会变化,导致缓存的不是最新的。由此带来了缓存的第一个重要问题:1.是否命中了缓存;2.命中的缓存是否足够新(需要通过再验证与服务端交互去判断)。

  • 命中
  • 未命中
  • 再验证命中(缓慢命中)
  • 再验证未命中
与命中相关的示意图:


速度排名:命中>再验证命中>未命中=再验证未命中。

对于服务端而言,已缓存的文档A可能会出现3个情形:1.文档A不变;2.文档A变化了;2.文档A被删除了。当一个带有缓存验证相关的请求头:If-Modified-Since的get类型的http请求达到服务端时,会相应地出现以下3个情形:
  • 再验证命中:从缓存读取文档A,返回304 Not Modified
  • 再验证未命中:由服务端读取文档A,返回200 OK
  • 对象删除:返回404 Not Found

命中率 2个衡量指标

  • 文档命中率——缓存服务的请求与总请求的比值,40%是比较合理的;
  • 字节命中率——缓存提供的字节数与总传输的字节数的比值

细心的读者会发现,缓存命中和缓存再验证命中的响应码都是200 OK,那么如何区分响应到底是缓存还是原始服务器返回的呢?HTTP的如下两个首部可以提供线索:

  • Via——添加额外的信息说明缓存发送的情况
  • Date\Age——Date < 当前时间,则来自缓存

2)缓存分类:

按照拓扑结构:


  • 私有缓存
  • 共有代理缓存
代理缓存的层级结构:


介绍了其它的结构:网状缓存及其内容路由功能,此外还有HTTP不支持的对等(兄弟)缓存

3)web缓存工作机制

流程图:


关键点:

1.新鲜度检测
缓存可以将服务端的文档副本保留一段时间,在这段时间里认为文档是新鲜的,缓存可以直接返回文档给客户端。一旦副本停留在缓存上的时间超过了限值,在提供文档之前,缓存就必须先与服务器进行一次确认,查看文档是否发生了变化。通过以下两个首部,服务器可以向每个文档添加一个过期日期,在特定范围内,可以认为文档是新鲜的。
  • Expires :HTTP 1.0+提供,取绝对时间
  • Cache-Control:max-age: HTTP 1.1提供,取相对时间(推荐)
2.再验证方法
一旦新鲜度检测发现缓存的文档不再新鲜,则缓存需要与服务器进行确认的过程被称为再验证过程,HTTP提供了如下几个验证首部:

  • If-Modified-Since/Last-Modified
  • If-None-Match/Etag
带有If-Modified-Since 首部的请求被称为IMS请求,表示只有自某日期之后资源发生了变化,才会指示服务器执行请求。这被称为条件方法,条件为假,服务器不返回文档主体,状态码304;条件为真,返回服务端文档,并携带新首部和过期时间,状态码200。

带有If-None-Match首部的请求称为实体标签再验证请求,解决了一些场景下仅仅通过最后的修改时间判断缓存是否发生变更不准确或者不支持的问题。比如:更新时间变了内容可能不变、一些内容的变更无关紧要、不提供最后的修改时间、实时性要求高的场景以秒为单位不够精准。实体标签是加到文档上的引用字符串,当服务器上的文档变更,就可以修改这个标签来说明存在新的版本。

另外,值得说明的是,当以上两个再验证首部同时存在时,只有条件都满足时,才会返回304响应。

4)缓存控制

服务端可以通过给响应附加如下首部来控制文档的缓存存活时间。(按优先级排序)

  • Pragma:no-store —— 为了向下兼容
  • Cache-Control:no-store —— 禁止缓存对服务端响应进行复制,缓存将转发no-store响应,并删除缓存对象;
  • Cache-Control:no-cache —— 告诉缓存在未与服务器进行再验证之前,禁止向请求方提供缓存,此时缓存还是可以保存副本的;
  • Cache-Control:must-revalidate —— 告诉缓存可以提供一些过期的缓存,只是需要再次和服务器验证之后才能提供;
  • Cache-Control:max-age —— 表示自服务器将文档传递到缓存之时算起,多少秒之内可认为此文档是否是新鲜的
  • Expires —— 同上,这个这里是一个绝对时间(依赖时钟同步,故不推荐使用)

5)与缓存相关的HTTP首部汇总

age  —— 响应首部 告诉接收端响应以及产生了多久了

Cache-Control —— 通用首部 缓存控制相关一系列

Date ——通用首部 表示请求或者响应报文创建的时间

Expires —— 实体首部 表示响应失效的时间

Etag —— 实体首部 用于标识资源

If-Modified-Since/If-Unmodified-Since —— 请求首部 条件方法

IF-Match/If-None-Match ——请求首部 也是条件方法,用实体标记来判断而不是日期

If-Range ——请求首部 也是条件方法,用于某个范围的条件匹配

Last-Modified——实体首部 提供了实体最近一次的修改相关信息

Pragma —— 用于随报文一起传递指令,虽然广泛应用,但不是所有的程序都支持,通常与no-cache一起使用,等价于Cache-Control的no-cache

Via —— 通用首部 用于报文在经过代理和网关时,对报文进行跟踪


补充阅读:

浏览器缓存机制相关:

www.cnblogs.com/1zero1/p/11…

www.infoq.cn/article/8VU…

zhuanlan.zhihu.com/p/93357692