Web缓存解决方案

缓存是构建于HTTP统一接口之上的最有用功能之一。能够利用缓存减小终端用户感知到的延时,增长可靠性,减小带宽使用和成本,下降服务器负载。缓存无处不在,能够在服务器网络里,内容分发网络(Content delivery network,简称CDN)或是客户端网络里(一般被称为转发代理Forward Proxy)。数据库

  1. 如何设置过时缓存头
    当缓存能够在不访问源服务器时作出尽量多的响应时,它是最高效的。设计过时缓存(Expiration Caching)就是为了下降源服务器收到的请求数量,同时减小应用程序使用的带宽。过时缓存基于Cache-Control和Expires这两个头,它们指导客户端和缓存在一段指定时间内保存从服务器返回的表述副本。在这个时间窗口之内,甚至超出该时间窗口,缓存能够对后续请求作出响应,无需访问源服务器。

    下面是Cache-Control指令列表及其适用性:

    public 默认指令。当请求是通过身份验证的,但您仍但愿共享缓存提供缓存响应时,也可使用该指令。
    private当响应专属于某个客户端或用户时,使用该指令。任意客户端缓存(如浏览器缓存或转发代理)均可以缓存表述,但诸如服务器缓存或网络之类的共享缓存则不能进行缓存。在基于客户端或用户身份验证来提供表述的时候添加该指令。
    no-cache和no-store 经过这些指令能够避免缓存存储或提供已经缓存的响应。如非必要,通常不使用这些指令。
    max-age该指令的值即为新鲜寿命,单位为秒。
    s-maxage这个指令与max-age相似,但只对共享缓存有意义。在源服务器同时设置了max-age和s-maxage时,缓存会使用s-maxage头。实际上,单独设置max-age指令就足够了。
    must-revalidate要求缓存在提供陈旧的表述前先检查源服务器。
    proxy-revalidate只应用于共享缓存。
    最佳过时缓存的关键是为资源表述计算一个合理的新鲜寿命值。若是有历史信息,例如表述的更新日志,能够参考它们来创建基线寿命。若是没有此类数据,能够先从一个合理的推测值出发,在获取更多信息后对其作出调整。一般这些信息源自于您发现某个客户端看不到最近更新的表述。
    相似Squid这样的缓存还支持两个Cache-Control头的扩展指令——state-if-error和state-while-revalidate。服务器能够用stale-if-error来告诉缓存,它们能够在指定时间间隔内继续提供陈旧的响应。
  2. 什么时候设置过时缓存头
    HTTP规定了什么是能缓存的,什么是不能缓存的,缓存也可能只实现了部分HTTP缓存协议。
    为全部带成功响应码的GET和HEAD请求的响应设置过时缓存头。虽然POST是可缓存的,但缓存会把该方法视为不可缓存的。其余方法无需设置过时缓存头。
    除了带200(OK)响应码的成功响应,还能够考虑缓存待3**和4**响应码的HTTP头,这能减小由客户端错误带来的流量。这种作法被称为消极缓存(negative caching)。
     
    300(multiple choices)带这个状态码的表述不太可能常常发送变化,缓存此类应答能够下降服务器负载。
    301(Moved Permanently)当资源永久移动时,那些将URI存储在数据库中的客户端可能不会修改这些URI。在这种状况下,缓存能够不用访问源服务器,直接提供重定向响应。
    400(Bad Request)当服务器返回该状态码时,客户端按理说不应重复请求,但出于软件错误或恶意攻击等缘由,有些客户端会重复发起请求。
    403(Forbidden)若是服务器永久拒绝服务该资源,请为其添加缓存。
    404(Not Found)该资源不存在,并且不必让服务器仅为失败生成表述。
    405(Method Not Allowed)客户端可能会由于软件错误而重复发送此类请求。
    410(Gone)资源再也不存在了,因此缓存应该尽量久地提供错误响应。
  3. 什么时候以及如何在客户端使用过时缓存头
    除非你是在构建一个封装在压缩包内的、须要用户安装并运行的客户端应用程序,不然应该避免在客户端应用程序中实现对过去缓存的支持。能够在客户端网络中部署一个转发代理缓存,避免在客户端代码中实现本身的缓存层。
    一般状况下,客户端应独立于过时缓存以外。理论上是有可能构建支持HTTP缓存协议的客户端应用程序的。举例来讲,常见的浏览器实现了过时缓存,并将表述存储在内存或文件系统之中。实际上,在客户端应用程序中构建并维护一个缓存是项很麻烦的工做。它涉及正确地实现no-store,no-cache和must-revalidate这样的过时指令,还要遵循Vary头的内容。在同一个运行时内放入缓存还会形成客户端应用程序代码与缓存代码争夺内存与CPU资源,这会让客户端的调优变得更加困难。
    相较之下,在客户端和服务器之间放置一个转发代理缓存更容易一些。不涉及任何开发活动,你就能够坐享通过精心测试的、健壮的缓存基础设施所带来的好处,无须本身构建。这么作还为往后扩展留下了空间,你能够架设一个全部客户端共享的转发代理服务器集群。
    若是客户端和服务器在同一个网络里,不必定须要转发代理。服务器上能够部署一个被全部客户端共享的缓存。但若是客户端是在和一个其余网络中的第三方Web服务交互,那么使用转发代理能够帮助减小客户端与服务器之间往返请求次数。
  4. 如何支持复合资源的缓存
    基于那些对新旧程度有强烈要求的数据来制定缓存决策,根据它们的变动频率来设置过时头。
    相比其它类型资源,复合资源实现缓存更为复杂,此类资源包含与其余资源重叠的数据,它们可能会有不一样的过时时间。
    复合资源是便利性与缓存效率之间权衡的一个好例子。对客户端而言,复合资源用起来很方便,但服务器要提供最新的资源却代价很大。
    一个解决办法是:将复合资源打散成三个资源,但这就强迫客户端发起屡次请求来获取数据。换言之,服务器须要考虑利害关系并作出权衡。当资源的表述粒度较粗时,就会发生这种状况,有可能会以独立资源的方式来提供表述中所含的数据。
  5. 如何保持新鲜且温暖的缓存缓存支持的众多挑战之一就是保持缓存的“新鲜”(最新状态)和“温暖”(非空),就算客户端没有发起请求时也是如此。以一个照片分享服务为例,在用户上传照片后,全部针对这些照片的缓存都是空的,所以服务器不得不生成照片的表述。相似的,当引入一个新的缓存时,它是空的,随着客户端开始发起请求后,它才会慢慢有内容。当缓存处于新鲜状态时,其中包含最新的表述。一个“温暖”的缓存能避免冷启动问题。可是,预先保持缓存的新鲜与温暖不在HTTP范畴以内。尽量地让过时时间与更新频率保持同步。当这点很难作到时,实现一些后台进程来监控数据库变动,定时执行无条件GET请求来刷新缓存。在定时调度这些请求时,必定要考虑到数据库复制的延迟。若是正在使用Squid,可使用HTTP缓存频道扩展(HTTP cache channel extension)向缓存传播资源更新。在HTTP中,当客户端提交PUT,POST或DELETE请求时,要求缓存做废表述。此后,客户端再对同一资源发起GET或HEAD请求时,缓存就能从源服务器得到一个新的表述。尽管这种作法不过高效(由于缓存没法保持非空状态),但它却保证了客户端能得到最新的表述。现实中,你的网络里可能有多个应用程序会读写相同的数据存储,只要其中任意应用程序的写操做绕过HTTP缓存和服务器,那么就会致使缓存的表述变旧。考虑如下场景:服务器上可能会有每晚执行的定时任务,更新摘要数据表以反映日间的工做。这个更新可能直接发生在数据库层面上,不会有任何HTTP请求。但你可能缓存了这个资源,一旦定时任务执行了,存储在缓存中的应答就旧了。普遍分布的数据存储在一天里可能会周期性地进行复制。数据的改变不会反映在所有的缓存里。大型应用程序可能会有一个或多个客户端或服务是使用自定义协议来更新数据的。只要使用这些服务就能够在不经过HTTP的状况下改变数据库,此时缓存并不知道资源发生了变化。
相关文章
相关标签/搜索