web缓存基础:术语、http报头和缓存策略

对于很多人来说,去访问某一个站点,若是该站点能够提供智能化的内容缓存来提高用户体验,那么最终该站点的访问者将络绎不绝。缓存或者对之前的请求临时存储,是http协议实现中最核心的内容分发策略之一。分发路径中的组件均可以缓存内容来加速后续的请求,这是受控于对该内容所声明的缓存策略。接下来将讨web内容缓存策略的基本概念,具体包括如如何选择缓存策略以保证互联网范围内的缓存能够正确处理的您的内容,并谈论下缓存带来的好处、副作用以及不同策略能带来的性能和灵活性的最大结合。

1、什么是缓存

缓存(caching)是一个描述存储可重用资源以便加快后续请求的行为术语。有很多类型的缓存,每一种都有自身的特点,应用程序缓存和内存缓存由于其对特定回复的加速,都比较常用。那么web缓存是一种不同类型的缓存。web缓存是http协议的一个核心特性,它能最小化网络流量,并且提升用户所感知的整个系统响应速度,内容从服务器到浏览器传输过程中,每一个层面都可以找到缓存的身影。web缓存根据特定的规则缓存相应的http请求的相应,对应的缓存的内容在后续的请求中直接满足请求,而不是重新发送请求到web服务器。

好处

有效的缓存技术不仅可以帮助用户,还可以帮助内容的提供者,带来的好处如下

 (1)、减少网络开销:内容可以在从内容提供者(服务器)到内容消费者(客户端)之间的网络路径中,很多地方都可以缓存。当内容在离消费者更近的地方被缓存起来,由于缓存的存在,请求将不会消耗额外的网络资源。

(2)、加快响应的速度:由于并不是必须通过整个网络往返,缓存可以使内容获得更快。缓存一般放在离用户更近的地方,例如浏览器缓存,是的内容的获取几乎是瞬时的

(3)、在同样的硬件上提供速度:对于保存原始的内容的服务器来说,更多的性能可以通过允许激进的缓存策略从硬件上压榨出来,内容提供者通过利用分发路径上某一个强大的服务器来应对特定内容负载的冲击。

(4)、网络中断时内容依旧可以用:使用某种策略,缓存可以保证在原始服务器变得不可用,相应的内容对用户依然可用。

术语

1、原始服务器:内容的原始存放地点。比如web服务器。可以为任何不能从缓存中得到内容进行回复。并负责设置所有的内容缓存策略

2、缓存命中率:一个缓存的有效性是依照缓存的命中率来度量。它是根据得到数据请求次数与所有请求次数的比率。缓存命中率高意味着有很高的比率数据是从缓存中获取到数据的,也是web管理员所看到的

3、新鲜度(有效期):用来描述一个缓存中的项目是否依旧适合返回给客户端。缓存中的内容只有在制定的新鲜度内才会返回。

4、过期内容:缓存中根据缓存策略的新鲜期(有效期)设置已过期的内容。过期的内容被标记为“过旧‘,通常过期内容不能用于回复客户端的请求,必须重新从原始服务器请求新的内容或者至少验证缓存的内容是否依然准确。

5、校验:缓存中过期内容可以验证是否有效,以便刷新过期时间。验证过程包括联系原始服务器以检查缓存数据是否依旧是最新版本

6、失效:根据过期时间移除缓存中对应的内容过程;当内容在原始服务器上已被改变时就必须这样做,因为缓存中过期的内容会导致客户端发生问题。

什么能被缓存

某些特定的内容比其他内容更容易缓存;对于多数站点来说,一些适合缓存的内容:

1、logo和商标图像

2、普通不变化的图像(如导航图标)

3、css样式表

4、普通的js文件

5、可下载的内容

6、媒体文件

这些东西更倾向于不经常改变,所以长时间的对他们进行缓存能获得好处

一些项目在缓存中必须注意的地方:

1、html页面

2、会替换改变的图像

3、经常修改的js和css

4、需要有认证后的cookie才能访问的内容

一些不适合被缓存的东西:

1、与敏感信息相关的资源(银行数据等)

2、用户相关经常改动的数据

除上面的规则外,还需要根据自身的情况设定一些规则以便更好的缓存不同种类的内容。例如如果登录的用户都看到同样的网站视图,就应该在任何地方缓存这个页面;若是登录的用于看到的特定的视图,那么就不需要在任何中介节点中缓存该内容,而是在用户的浏览器中缓存该内容。

web内容缓存位置

web内容会在整个分发路径中很多不同的位置被缓存:

1、浏览器缓存:web浏览器自身维护一个小型的缓存。典型地浏览器使用一种策略制定缓存最终要的内容;比如是用户相关的内容或者可能会再次请求且下载的代价较高

2、中间缓存代理:任何客户端和基础架构服务器之间都可以缓存一些内容。这些缓存可能有isp(网络服务提供者)或者独立组织提供。

3、反向缓存:您的服务器基础架构可以为后端的服务实现自己的缓存,如果实现缓存,那么便可以在处理请求的位置返回相应的内容而不是每次请求都使用后端服务

上面这些位置通常都可以根据自身的缓存策略和内容源的缓存策略缓存一些相应的内容。

缓存头部

缓存策略依赖于两个不同的因素。所缓存的实体本身需要决定是否应该缓存可接受的内容,它可以缓存部分内容,但不能缓存超过限制的内容。

缓存行为主要由缓存策略决定,而缓存策略由内容拥有者设置。这些策略由内容拥有者设置。这些策略上主要通过特定http头部表达

经过不同的http协议变化,出现了一些不同针对缓存方面的头部,它们复杂度各不相同,需要注意如下

1、**Expires**:尽管使用范围相当有限,但是Expires头部简单明了的,通常它设置一个未来时间,内容会在此时间过期。这时任何对同样内容的请求都应该回到原始服务器处;这个头部或许仅仅适合回退模式(fall back)

2、**cache-control**:只是expires的加强版;被很好支持,且拥有更加灵活的实现。在大多数案例中,比expires更好;但是同时设置expires和cache-control也无妨。

3、**ETag**:用于缓存验证。原服务器可以在首次服务一个内容为该内容提供一个独特的etag。当一个缓存需要验证这个内容是否即将过期,他将会将相应的etag发送回服务器。如果原服务器和客户端一致,则告诉客户端一致;或者更新内容。

4、**last-modified:这个头部指明了相应的内容最后一次被修改的时间。他可能回作为保证内容新鲜度的验证策略的一部分使用。

5、**content-length**:尽管并没有在缓存中明确涉及;content-length头部在设置缓存策略中很重要;某些软件如果不提前获知内容的大小留出足够内容,则会拒绝缓存该内容。

6、**vary**:缓存系统通常使用请求主机和路径作为存储资源的键;当判断一个请求是否是请求同样内容,vary头部可以被用来提醒缓存系统需要注意另一个附加头部;通常被用来告诉缓存系统同样注意accept-encoding头部,以便缓存系统能够区分压缩和未压缩的内容。

vary头部隐语

vary头部提供存储同意内容的不同版本的能力;代价降低了缓存的容量;在使用accept-encoding时;设置vary头部允许明确的区分压缩和未压缩的内容;这在服务某些不能压缩数据的浏览器很重要,并提供基本的可用性。vary的一个典型的值是accept-encoding,有三个可选值。

一看上去以为user-agent这样的头可以区分移动浏览器和桌面浏览器;以便您的站点提供差异化服务;但是user-agent字符串是非标准的结果将造成在中间缓存中同一个内容很多版本的缓存;这回导致缓存命中率降低;vary头部慎用;特别是在你不具备控制中间缓存中使请求标准化的能力(也许可以,比如您可以控制cdn)

缓存控制标志怎样影响缓存

1、一些可以使用指示内容缓存策略的cache-control的选项如下:

no-cache:指示所有的缓存内容在新的请求到达时必须先重新验证,在发送给客户端,这条指令实际将内容立刻标记为过期,但是允许通过验证手段重新验证以避免重新下载整个内容。

no-store:指示缓存的内容不能以任何方式被缓存,他适合在回复敏感信息时设置。

public:将内容标记为公有的,这意味着它能被浏览器和其他任何中间节点缓存,通常对于使用http请求其回复被默认标记private的;public标记会覆盖这个设置。

private:内容标记为私有的。私有数据可以被用户浏览器缓存;但不能被任何中间节点缓存;通常用于用户相关的数据。

max-age:指示缓存内容的最大生存期;它在最大生存期后必须在原服务器处被验证或被重新下载;在现代浏览器中这个选项大体上取代了 expires头部;浏览器也将其作为决定内容新鲜度的基础;该值以秒为单位;最大可以表示一年新鲜期

s-maxage:很类似max-age,指明了内容能被缓存的时间;区别是这个选项只在中间节点的缓存中有效,结合s-maxage和max-age可以构建灵活的缓存策略

must-revalidate:指明了max-age、s-maxage、expires头部指明的新鲜度必须严格遵守;避免了缓存数据在中断类似的场景被使用。

proxy-revalidate:和上面选项有着一样的作用,不过只应用于中间的代理节点;在这种情况下,用户浏览器可以在网络中断时使用过期内容;但是中间缓存内容不能用于此目的

no-transform:这个选项告诉缓存在任何情况下都不能因为性能的原因修改接受到内容,这意味缓存不允许压缩接收到的内容(没有从原始服务器接受过压缩版本的该内容),并发送。

这些选项能够以不同的方式结合已获得不同的缓存行为,一些互斥的值如下

no-cache、no-store以及其他前面未提到的选项指明常用的缓存行为。

public和private

如果no-store和no-cache都被设置了,那么no-store会取代no-cache,对于非授权的请求回复;public是隐式设置;对于授权的请求回复,private是隐性设置;可以通过在cache-control头部指明相反的选项已覆盖

开发缓存的一种策略

在理想情况下,任何内容都可以被尽可能缓存,而服务器只需要偶尔的提供验证内容即可。但是在现实中很少发生,因此您应该尝试设置一些明智的缓存策略;以长期缓存和站点改变的需求间的平衡

常见问题

在很多情况中,由于内容被产生的方式或者内容的特性这些都不应该被缓存,另一些设置缓存可能面临的问题外边缓存未过期,新的数据已经产生。这些都是经常遇到的问题,会影响缓存的性能和数据的准确性,然而,我们可以通过开发提前遇见这些问题的缓存策略来缓存解决这些问题。

一般性建议

1、为图像、css和共享内容建立特定文件夹:将内容放到特定文件夹是的方便从站点任何位置引用该资源

2、使用同样的url来表示相同的内容:由于缓存使用内容请求中主机和路径作为键,因此应保证所有页面中的内容引用方式相同,前一个建议可以让这点更加容易做到

3、尽可能将主机脚本和外部资源本地化:使用js脚本和其他外部资源,如果上游没有提供合适的缓存头部,那么应该考虑将这些内容放在自己的服务器上。同时需要注意上游的任何更新,便于更新本地的拷贝

4、对于缓存内容收集文件摘要:静态的内容比如css和js文件通常比较适合收集文件摘要;为文件添加一个特殊标识符(通常为文件的哈希值)可以在文件修改后绕开缓存保证新的内容被重新获取;有很多工具可以帮助创建文件摘要并且修改html的引用。

对于不同的文件正确的选择不同的头部的参考:

1、允许所有的缓存存储一般内容:静态内容以及非用户相关内容应该在分发连的所有的节点被缓存,这使得中间节点可以将该内容回复给多个用户

2、允许浏览器缓存用户的相关数据:对于每个用户的数据,通常在用户的浏览器中缓存是可以被接受且有意的。缓存在用户自身的浏览器能够使用户在接下来的浏览器中能够瞬时读取到,但是这些内容不适合在任何中间代理节点缓存

3、将时间敏感内容作为特例:如果您的数据是敏感的。那么相对上面的参考,应该将这些数据最为特例,以保证过期的数据不会再关键的情况下被使用。例如您的站点有一个购物车,它应该立刻反应购物车里面的物品,依据内容的特点:可以在cache-control头部中使用no-cache或no-store选项

4、总是提供验证器:验证器使用过期的内容可以无需下载而得到刷新,设置etag和last-modified的头部将允许缓存向原始服务器验证内容,并在内容未修改刷新该内容新鲜度以减少负载

5、对于支持内容设置长的新鲜度:为了更加有效利用缓存,一些作为支持性的内容应该被设置较长的新鲜期;这通常比较适合图像和css等由用户请求用来渲染html页面的内容。和文件摘要在一起,设置延长的新鲜期将允许缓存长时间存储这些资源。如果资源发生改变,修改文件摘要将会使缓存的数据无效并触发对新的内容下载,那时新的支持内容会继续被缓存。

6.对于父内容设置短的新鲜期:为了使得前面的模式正常工作;容器类的内容应该相应的设置短的新鲜期,或者设置不全部缓存。这通常是在其他协助内容使用html页面,这个html页面将会被频繁使用、下载;使得它能快速响应。支持性的内容因此可以被尽量缓存。

关键之处在于达到平衡,一方面尽量的进行缓存,另一方面未来保留当改变发生时从而改变整个内容的机会,因此您的站点应该同时具有:

尽量缓存内容

拥有短的新鲜期的缓存内容,可以被重新验证

完全不被缓存的内容

这样的目的将内容尽可能的移动到第一个分类(尽量缓存)的同时,维持一个可以接受的缓存命中率

结论

花时间确保您的站点使用了合适的缓存策略可以保证服务同样内容的同时减少带宽的使用,可以靠同样的硬件处理更多的流量,或者最重要的提高用户的体验,是的他们更愿意访问您的站点。

(该文虽然与原文有出入,但是隶属于原文,同时感谢不记得名字的原文作者!!!)

相关推荐