美文网首页
《HTTP权威指南》笔记:第七章-缓存

《HTTP权威指南》笔记:第七章-缓存

作者: 前端艾希 | 来源:发表于2021-11-17 16:48 被阅读0次

    一、命中和未命中缓存

    使用缓存的副本为到达缓存的请求提供服务被称为缓存命中(cache hit),如果没有已缓存的副本提供,而将请求转发给源服务器,被称之为缓存未命中(cache miss)

    1.1 再验证

    WEB缓存对已缓存的副本进行“新鲜度检测”,会向源服务器发送一个小的再验证请求,如果缓存仍然“新鲜有效”,那么服务器会返回一个304 not modified,然后缓存将副本提供给客户端。这被称为再验证命中或者缓慢命中

    缓存一般会使用:(1)if-modify-since;(2)if-match;等HTTP首部进行再验证,会有以下结果:

    1. 再验证命中,服务端响应304
    2. 再验证未命中,服务端响应200并且带有完整内容。
    3. 对象被删除,服务端响应404,缓存清除该资源副本。

    1.2 缓存命中率

    由缓存提供服务所占的比例被称为缓存命中率,这个数值在0 ~ 1之间,对于现代中等规模以上的WEB应用来说,命中率保持在40%以上就达标了。

    1.2 字节命中率

    字节命中率直接体现对流量的节省,也能显著的降低时延,但是两者都是评价缓存性能的重要指标。

    1.3 区分命中与未命中

    检查HTTP报文的Date首部,如果时间早于请求时间,那么就是来自缓存,否则是来自服务端。

    二、缓存的拓扑结构

    缓存可以是单用户的(私有缓存),也可以是多用户共享的(公共缓存),下面是常见的缓存结构:

    client -> private cache -> server
    client -> public cache -> server
    client -> private cache -> public cache -> server
    

    2.1 私有缓存

    Web浏览器中有内建的私有缓存。

    2.2 公共代理缓存

    公共缓存时特殊的共享代理服务器,被称为缓存代理服务器

    2.3 代理缓存的层次结构

    在代理缓存层次结构中,在靠近客户端的一级缓存中未命中的请求会被导向更高的父缓存,具体结构如下:

    client/(private cache) -> first cache -> parent cache -> server
    

    2.4 网状缓存、内容路由以及对等缓存

    有些网络结构会哦固件负载的网状缓存(cache mesh),与缓存之间会以更加复杂的方式对话,可以做出动态缓存通信决策,决定与哪一个父缓存通信,或者直接与源服务器通信,也可将这种结构称为内容路由(content router),它具有以下功能:

    • 根据URLparent cacheserver之间做动态选择。
    • 根绝URL动态选择parent cache
    • 允许该结构其他缓存对缓存的副本进行访问,但是不允许外网流量访问。

    三、缓存处理步骤

    对一条HTTP GET报文的基本缓存处理步骤为:

    1. 接收。
    2. 解析,提取报文的URL以及headers
    3. 查询,在本地查询是否有已保存副本。
    4. 新鲜度检测。
    5. 创建报文,根据检测结果创建响应报文。
    6. 日志,可选的记录日志。

    四、保持副本新鲜

    4.1 过期日期和使用期

    服务器使用HTTP/1.0+expires或者HTTP/1.1cache-control:max-age=value来规定缓存的使用时间区间。expires是绝对时间,依赖于客户端的始终,而cache-control使用的是相对时间,所以现在更倾向使用后者。

    4.2 服务器再验证

    如果已缓存的内容到期了(强缓存),那么会重新请求服务器对资源进行验证,如果未修改,返回304,更新缓存副本的首部;如果已修改,则返回200,然后丢弃原来的副本,缓存新的副本。

    4.3 条件再验证

    如果采取了协商缓存策略,那么可以发起条件GET,只有当条件满足了,服务端才会返回对象。HTTP定义了5个条件首部:

    1. if-modified-since:<date>,如果从指定日期之后文档修改了,则从服务端返回新的对象(响应报文配合last-modified使用)。
    2. if-none-match:<tags>,如果tag与服务端指定资源的标记不同,则条件为true,返回新对象(响应报文配合etag:xxx使用)。
    3. if-unmodified-since:<date>,在进行部分文件传输时,获取其他部分之前要确保文件未发生改变。
    4. if-range,针对不完整文档的缓存。
    5. if-match,与服务器通信时的并发控制。

    4.3.1 if-none-match的必要性

    1. 有些文档会被周期性重写,尽管内容没改变,但是时间改变了。
    2. 有些文档的修改不重要,也许只是修改了注释之类的,则不需要重新获取。
    3. 有些服务器无法准确的判定最后修改日期。
    4. if-modified-since的时间粒度是秒,而有些文档可能在1秒内发生数次变化。

    4.3.2 使用if-none-match和if-modified-since的时机

    HTTP/1.0可能不能理解实体标签,所以服务端返回响应的时候最好同时返回last-modifiedetag这样可以使HTTP/1.0也能正常响应,如果服务端同时返回这两个首部,那么只有当这两个条件都满足,服务端才能返回304

    五、如何控制缓存

    按照优先级递减的顺序,服务端可以设置以下首部到响应报文中:

    • cache-control:no-store
    • cache-control:no-cache
    • cache-control:must-revalidate
    • cache-control:max-age
    • expires
    • 不设置相关头部,让缓存自己决定过期时间,可能是首部的date减去last-modified的五分之一(知乎上有人称之为启发式缓存)

    5.1 缓存首部

    • cache-control: no-store,会阻止缓存对响应进行复制即不缓存。
    • cache-control:no-cache,可以被私有缓存复制保存在本地,但是在提供给客户端使用必须会与服务端进行再验证。
    • cache-control: max-age=100,缓存的活跃时间。
    • cache-control:s-maxage=100,针对公共缓存设置的缓存活跃时间。
    • expires:Fri,05 Jul 2020,05:00:00 GMT,绝对活跃时间,即在指定时间之前是活跃的。
    • cache-control: must-revalidate,如果不添加这个首部,有的缓存为了提高性能会给客户端提供过期的副本,添加这个首部告诉缓存在副本过期后必须重新请求,如果服务端不可用就必须返回504 gateway timeout

    5.2 试探性过期

    如果响应首部没有设置副本的过期时间,那么缓存会采取一定的算法计算出一个试探性的生存周期,比较常见的是LMF-Factor算法,具体计算公式为:lm_facotr * max(0, date - lastModified),一般lm_factor会取0.2。有的缓存保守起见会直接默认副本活跃时间为0,有的缓存则会设置最大值为1天或者1周。

    5.3 客户端的新鲜度限制

    当我们点击浏览器的刷新按钮重载页面时,一般来说浏览器会强制刷新缓存,客户端可以在请求首部加入cache-control以加强或者放松对过期时间的限制:

    • max-stale[=<s>],如果只设置了max-stale表明客户端可以接受过期的缓存,如果设置了max-stale=100,就说明该缓存的副本在100s内不会过期,相当于是放松了对缓存过期时间的管控。
    • min-fresh=<s>,要求在指定时间内是有效的。
    • max-age=<s>,生命周期小于设置的值的副本就会被认为过期,相当于缩短了服务端设置的max-age
    • no-cache,强制缓存进行再验证。
    • no-store,强制缓存删除相关文档。
    • only-if-cached,只有当缓存中有该请求的副本,客户端才能获取到该对象(意思是必须从缓存取而不是服务器?)

    参考文献

    [1]《HTTP权威指南》

    相关文章

      网友评论

          本文标题:《HTTP权威指南》笔记:第七章-缓存

          本文链接:https://www.haomeiwen.com/subject/mroltrtx.html