Web缓存服务器是可以自动保存常见文档副本的HTTP设备,当Web请求到达缓存服务器时,如果缓存服务器有副本,就可以从本地存储设备而不是原始服务器中响应请求。

Web缓存的优点

  • 缓存减少了冗余的数据传输,节省了网络费用
  • 缓存缓解了网络瓶颈、降低了距离时延,能够更快的加载页面
  • 缓存降低了对原始服务器的要求,降低了服务器的压力
  • 缓存有效的解决了服务器瞬时拥塞问题

有哪些缓存服务器

squid、varnish、nginx cache、Traffic Server

Web缓存的处理步骤

下图是缓存服务器的大致处理步骤,理论上的步骤已足够简单明了:

缓存的处理步骤

缓存新鲜度

在缓存服务器的处理步骤中新鲜度检测是最为关键的一步。所谓新鲜度检测就是检查缓存是否过期。下图是新鲜度检测的大致步骤:

新鲜度检测步骤

是否足够新鲜

如果缓存服务器存在某资源的缓存,首先需要判断该缓存是否足够新鲜,也就是是否过期。

资源是否足够新鲜是用HTTP响应首部表示的,有两个响应首部可以用于新鲜度检测。当检查是否新鲜时,缓存服务器读取上次储存的原始服务器的响应首部进行检查。

  • Cache-Control:max-age。max-age定义了资源从生成开始的最大使用期,单位是秒。例如,Cache-Control:max-age=3600表示1小时后过期。
  • Expires。指定一个绝对的过期日期。

缓存服务器可以根据这两个首部之中的一个来判断资源是否过期。如果没有过期,就可以使用缓存服务器缓存的资源,如果过期了,就需要与原始服务器进行再验证

与原始服务器进行再验证

如果缓存过期了,就需要与服务器进行再验证。缓存过期并不代表资源一定发生了变化,只说明需要与原始服务器进行再验证,让原始服务器告诉缓存服务器资源是否发生变化。

  • 如果验证之后,资源没有发生变化,也就是再验证命中或缓存命中,那么就可以用原始服务器返回的响应首部更新缓存服务器上的资源的过期时间。
  • 如果再验证未命中,说明资源发生了变化,就需要重新从服务器获取最新资源。
  • 如果服务器对象已经被删除了,服务器就响应404状态码,缓存也应该将其副本删除。

命中率

缓存提供服务的请求所占的比例被称为缓存命中率。

由于资源的大小时不同的,有时候缓存命中率并不能有效的反应缓存服务器的贡献,另一种度量标准叫字节命中率字节命中率表示缓存提供的字节在传输的所有字节中所占的比例。

如何与原始服务器进行再验证?

验证的方式有两种:用条件方法进行再验证强弱验证器

1. 用条件方法进行再验证

HTTP定义了7个条件请求首部,对缓存再验证来说,最有用的2个首部是:If-Modified-SinceIf-None_Match

条件请求首部。有时客户端希望为请求加上某些限制,要求服务器再对请求响应之前,确保某个条件为真。 HTTP定义了7个条件请求首部:

首部 描述
Expect 允许客户端列出某请求所要求的服务器行为
If-Match 如果实体标记与文档当前的实体标记相匹配,就获取这个这份文档
If-None_Match 如果提供的实体标记与当前文档标记不相符,就获取文档
If-Modified-Since 除非在某个指定日期之后资源被修改过,否则就限制请求
If-Unmodified——Since 除非在某个指定日期之后资源没有修改过,否则就限制请求
If-Range 允许对资源的某个范围进行条件请求
Range 如果服务器支持范围请求,就请求资源的指定范围
  • If-Modified-Since。可以与服务器响应首部Last-Modified配合使用。当缓存服务器需要再验证时,可以将自己缓存的原始服务器响应首部的Last-Modified的日期附加到If-Modified-Since上。如果这个日期之后,服务器资源被修改了,原始服务器就会响应新的资源。否则原始服务器会返回304 Not Modified状态玛。
  • If-None_Match。有时仅仅使用使用最后修改日期不能满足需求,比如
      1. 有些资源可能会被周期性的重写,但实际上内容并没有改变;
      1. 有些服务器资源修改的频率很高,每秒修改多次;
      1. 有时资源的修改不重要,不需要让缓存更新。

在这些情况下,给资源加上标签就非常有用了。例如,If-None-Match:"v2.6","v2.5","v2.4"。那么只有在修改后的资源的tag不是这3个时才返回新的资源,否则返回304状态码。标签是从响应首部ETag获取的。

如何选择用哪个条件请求首部?

如果服务器回送了一个实体标签,HTTP/1.1 客户端就必须使用实体标签验证器。如果服务器只回送了一个Last-Modified值,客户端就可以使用If-Modified-Since验证。如果实体标签和最后修改日期都提供了,客户端就应该使用这两种再验证方案,这样 HTTP/1.0 和HTTP/1.1 缓存就都可以正确响应了。

2. 强弱验证器

控制缓存

服务器控制缓存

服务器可以通过 HTTP 定义的几种方式来指定在文档过期之前可以将其缓存多长时间。按照优先级递减的顺序,服务器可以:

  • 附加一个Cache-Control: no-store首部到响应中去;
    标识为no-store的响应会禁止缓存对响应进行复制。
  • 附加一个Cache-Control: no-cache首部到响应中去;
    标识为no-cache的响应,使用资源副本前,一定要到源服务器进行副本新鲜度校验
  • 附加一个Cache-Control: must-revalidate首部到响应中去;
    标识为must-revalidate的响应,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验
  • 附加一个Cache-Control: max-age首部到响应中去;
  • 附加一个Expires日期首部到响应中去;
  • 不附加过期信息,让缓存确定自己的过期日期。
    如果响应中没有Cache-Control: max-age首部,也没有Expires首部,缓存可以计算出一个试探性最大使用期。LM-Factor算法是一种很常用的试探性过期算法,如果文档中包含了最后修改日期,就可以使用这种算法。LM-Factor算法将最后修改日期作为依据,来估计文档有多么易变。

客户端控制缓存

Web 浏览器都有Refresh(刷新)或Reload(重载)按钮,可以强制对浏览器或代理缓存中可能过期的内容进行刷新。Refresh按钮会发布一个附加了Cache-Control请求首部的GET请求,这个请求会强制进行再验证或者无条件地从服务器获取文档。Refresh的确切行为取决于特定的浏览器、文档以及拦截缓存的配置。

指令 描述
Cache-Control: max-stale
Cache-Control: max-stale =
缓存可以随意提供过期的文件。如果指定了参数<s>,在这段时间内,文档就不能过期。这条指令放松了缓存的规则
Cache-Control: min-fresh= 至少在未来<s>秒内文档要保持新鲜。这就使缓存规则更加严格了
Cache-Control: max-age = 缓存无法返回缓存时间长于 <s> 秒的文档。这条指令会使缓存规则更加严格,除非同时还发送了max-stale指令,在这种情况下,使用期可能会超过其过期时间
Cache-Control: no-cache 除非资源进行了再验证,否则这个客户端不会接受已缓存的资源
Cache-Control: no-store 缓存应该尽快从存储器中删除文档的所有痕迹, 因为其中可能会包含敏感信息
Cache-Control: only-if-cached 只有当缓存中有副本存在时,客户端才会获取一份副本

缓存和广告

缓存的优点已经在文章开头写出,但是广告提供商并不一定完全喜欢缓存,因为很多广告收益是基于广告的点击量来确定的。但是缓存向原始服务器隐藏了广告的点击次数。

广告商为了确保缓存不会窃取他们的命中流量,可以采取的方法有:

  • 在内容上加上no-cache首部
  • 每次访问时重写广告URL
  • ?通过CGI网关提供广告
  • 缓存告诉原始服务器缓存服务器的命中次数
    • 每次访问缓存都与原始服务器再验证
    • 缓存将命中日志发送给服务器

参考资料