内容提要

  • 本章主要从缓存的架构、优势、节省带宽流量、提升响应及处理步骤等方面阐述了web缓存!

使用缓存的优点

  • 缓存减少了冗余的数据传输,因为毕竟每次http事务请求的东西都是一样的时候,多次发送同样的数据是不必要和冗余的!

  • 缓存缓解了网络瓶颈的问题,不需要更多的带宽就能够更快地加载页面!

  • 缓存降低了对原始服务器的要求,因为想象一下,从一个性能很差劲的原始服务器和从一个性能和牛逼的缓存服务器请求事务,肯定会弥补服务器的缺点的,同时也会减少服务器过载情况,因为大部分请求都由缓存代劳处理了!

  • 缓存降低了距离时延,因为从较远的地方加载页面会更慢一些!

冗余的数据传输

  • 每次都从原始服务器拿数据,那么带来的后果就是:多次发送重复的数据浪费流量、耗费昂贵的网络带宽从而降低传输速率、加大服务器的负载。而有了缓存之后这些问题都可以迎刃而解!

带宽瓶颈

  • 带宽瓶颈说明的问题:很多网络为本地客户端配置的带宽要比远程服务器配置的带宽要宽,如果在这种状况下客户端去请求远程服务器,那么客户端将会以一种的较低的速度去请求服务端,从而没有发挥出客户端带宽宽的长处!如果在客户端方向配置一个高速缓存服务器,那么就可以很快的得到响应,由此也看出带宽对报文传输速率的影响!

瞬间拥塞

  • 瞬间拥塞描述的是这样一种情况:一个爆炸性的新闻和热点事件,如果再没有配置缓存的情况下,那么在短时间之内,服务器将会收到突变的请求增长,负荷会爆炸性增长,肯定会吃不消的!但是有了缓存,可以大大分担服务器的负载数量!

距离时延

  • 距离时延说明的一个问题就是传输数据过程这个过程是需要时间的,而且路程越长,那么需要的时间也会越多,即时延越长。所以在距离客户端较近的地方部署缓存服务器,减小了传输路程,那么就减小了传输时延!

命中与未命中的

  • 缓存命中与缓存未命中:一次http事务请求如果是从得到的响应是从缓存得到的原始响应副本,那么这样的过程就称之为缓存命中。反之,如果缓存没有响应的副本,而要去请求原始服务,那么就把这个过程称之为缓存未命中!

  • http再验证:原始响应内容是在变化的,所以缓存应该在文档“过期时间”之后去验证缓存的副本是不是新鲜的,这个过程就叫做http再验证!如果再验证之后得知缓存副本是新鲜的,那么原始服务器返回304 not modified。此时,称之为再验证命中缓存慢命中!如果得知缓存不是新鲜的,那么服务器返回200 ok。此时,称之为再验证未命中!如果原始对象已经被删除了,返回404 not found响应。相应地缓存副本要删除。(注:虽然再验证命中需要跟原始服务器沟通一次,但是它与直接请求服务器相比,还是要快一点,因为再验证命中只是返回了一些新的过期时间有关的新首部而已,并没有发送主体对象。)

  • 命中率指由缓存返回副本事务在全部事务中所占的比例,称为缓存命中率。这个数据实际中意义不是很大!而字节命中率从资源大小总量的角度说明缓存命中所占的比例。因为他从数据流量的角度出发,所以实际中这个数据的意义挺大的!

  • 区分命中和未命中,简单来说,http没有相应的机制来告知客户端响应是从缓存得到的还是从原始服务器得到的!但我们可以从http响应报文首部中的date字段得知这一情况:如果这个字段的时间比当前时间更早得多,说明这是从缓存得到的,因为date描述的服务器第一次响应的时间,而缓存是不会对这个字段进行修改的!

缓存的拓扑结构

  • 缓存分为私有缓存(只为一个客户端服务,比如我们给浏览器配置的代理)和共有缓存(为多个客户端服务,现实中是以代理缓存服务器的形式踹出现)。

  • 代理缓存的层级结构:此种结构描述的以父、子层级出现的层次结构,同时离客户端越近的子缓存的命中率较低(较廉价),他们可以把请求上升到父缓存(较昂贵),从而在父缓存那里实现事务处理!

  • 代理缓存的网状结构描述的缓存结构并不是很明显呈现父子关系的结构,而是呈无规则的网状!这种结构的思想就是子缓存可以动态选择上一级缓存,从而实现更灵活的缓存控制!

缓存的处理步骤

  • 简单概括,即:
  1. 接收————解析————查询————新鲜度检测————创建响应————发送————记入日志
  • 第一步接收:读取网络连接http请求报文

  • 第二部解析:把报文解析为片段,并把首部放入到缓存易操作的数据结构中

  • 第三步查询:查找存下来缓存副本

  • 第四步新鲜度检测:说白了检查缓存副本是不是还有效的

  • 第五步创建响应:缓存服务器用原始服务器的缓存副本实现响应的起点,同时再在此基础上做一些修改,比如协议转换等

  • 第六步发送:发送报文

  • 第七步日志:事务完成之后,在日志文件插入一个条目,用以记录缓存处理情况,以及记录一些与缓存命中率的数据

保持副本的新鲜

  • 文档过期通过特殊的http首部cache-control和expires,http让原始服务器为每个文档设置一个“过期时间”!如:
  1. Cache-Control: Max-Age=484200
  2. Expires: Fri, 28 Oct 2016 03:03:47 GMT

上面的Max-Age是相对时间,以秒为单位,理解为使用期,expires为绝对时间,为到期时间。

  • 服务器在验证,描述的过期的文档并不是就是原始服务器的原始文档不一样了,而是需要向服务器发起新鲜度验证请求。

  • 用条件方法进行再验证:涉及到的两个首部为If-Modified-Since和If-None-Match。格式为:

  1. If-Modified-Since: <date>

实际上上面那个date为服务器响应报文里面Last-Modified的时间。

  • If-None-Match:实体标签再验证!此种机制主要跟If-Modified-Since不同在于:If-Modified-Since是根据修改时间来判断文档新鲜度的,但有些情况这样做是不适用的,因为比如我们只是加了注释什么的,其中实际内容是没有变化的,此时我们也应该认为文档是新鲜的!

  • 强弱验证器:描述的是一种对内容的更改“严不严重,影不影响主要含义”的实体标签验证!

缓存控制的能力

  • 缓存控制能力描述的是服务器可以通过设置相关首部来控制文档的缓存过期时间的能力!相关首部如:
  1. Cache-Control: no-store //不能缓存
  2. Cache-Control: no-cache //在没有对服务器验证之前不能提供内容
  3. Cache-Control: must-revalidate //严格遵守新鲜验证规则
  4. Cache-Control: max-age //设置多长时间的过期时间(相对时间)
  5. Expires: <date> //设置多长的过期时间(绝对时间)
  6. (试探性过期)不设置首部,让缓存来决定,这个方式涉及到一种算法,比如缓存服务器通过查看最后修改时间,从而得到该文档的修改频繁度,从而为其设置缓存过期时间

上面的优先级从上到下依次降低。

  • 客户端的新鲜度限制:Web浏览器都有Refresh(刷新)或Reload(重载)按钮,可以强制对浏览器或代理缓存中可能过期的内容进行刷新。Refresh按钮会发布一个附加了Cache-Control请求首部的GET请求,这个请求会强制进行再验证,或者无条件地从服务器获取文档。Refresh的确切行为取决于特定的浏览器、文档以及拦截缓存的配置。客户端可以用Cache-Control请求首部来强化或放松对过期时间的限制,先关首部介绍如下:
  1. Cache-Control请求指令
  2. 指令 目的
  3. Cache-Control: max-stale 缓存可以随意提供过期的文件。如果指定了参数<s>,在这段
  4. Cache-Control: max-stale = <s> 时间内,文档就不能过期,这条指令放松了缓存的规则
  5. Cache-Control: min-fresh=<s> 至少在未来<s>秒内文档要保持新鲜。这就使缓存规则更加严格了
  6. Cache-Control: max-age = <s> 缓存无法返回缓存时间长于<s>秒的文档。这条指令会使得缓存规则更加
  7. 严格,除非同时还发送了max-stale指令,在这种情况下,使用期可能会
  8. 超过其过期时间
  9. Cache-Control: no-cache 除非资源进行了再验证,否则这个客户端不会接受已缓存的
  10. Pragma: no-cache 资源
  11. Cache-Control: no-store 缓存应该尽快从存储器中删除文档的所有痕迹,因为其中可能会包含敏感信息
  12. Cache-Control: only-if-cached 只有当缓存中有副本存在时,客户端才会获取一份副本

设置缓存控制

  • 控制Apache的HTTP首部:默认没有开启,需要用到相关模块。如:
    • mod_headers:加载之后就能对相关首部进行配置了,如:
  1. <Files *.html>
  2. Header set Cache-control no-cache
  3. </Files>
    • mod_expires:mod_expires模块提供的程序逻辑可以自动生成带有正确过期日期的Expires首部
    • mod_cern_meta:略
  • 此外,客户端通过HTTP-EQUIV控制HTML缓存,但是值对html文件有用,这种方法并不是很好!

详细算法

  • 描述的与响应报文有关一些过期时间或使用时间的计算,详情请参看原书!

缓存广告

  • 因为缓存的存在,导致某些靠用户点击次数收费的广告的请求未达到原始服务,从而服务器很难对用户进行了多少次点击进行计数!一种解决方案就是配置缓存,每次访问时都与原始服务器进行再验证。这样,每次访问时都会将命中推向原始服务器,但通常不会传送任何主体数据。当然,这样会降低事务处理的速度。