首页 > ATS核心, 使用, 常用功能, 配置文件 > to cache or not to cache,一直是个大问题

to cache or not to cache,一直是个大问题

2014年6月12日     浏览数:8,030 发表评论 阅读评论

to cache or not to cache,一直是个大问题

对一个cache服务器来说,什么应该cache,什么可以cache,什么必须cache,什么能cache,什么不能cache,一直是非常非常棘手的问题,对一个新人来说,那就更难啦。然而,这个话题只要一扯开,必然是一通的争吵,这里我们先从ATS本身来讲起,逐步的讲透这些关键点。

当然,无论如何,你都应该好好看看RFC2612等几个关键的RFC文档,

从ATS的默认配置说起

你的服务器刚装好,那应该配置的默认配置,而如果使用的是ATS的默认配置,cache方面有这么些效果:

这个配置对一个cache服务器来说,非常保守,但是符合所有RFC的最严苛要求。对用户来说,是非常安全的设置,不会出现任何问题。使用cache系统,数据安全第一总是对的!

随着你对ATS的了解,恐怕就在想啊,我的命中率为啥这么低呢?我能不能把命中率从目前的50%,提高到60%呢?ATS这么强大,当然可以啊。先让我们仔细的分析一下,什么可以cache。

根据http/1.1的规则,协议上讲,可以cache的东西是蛮清楚的(当然,我说的是日常用到的都是蛮清楚的)。基本上也不外乎几个方面的:

  1. 返回头里cache-control明确规定的,必须cache
  2. 有些条件的,选择性cache

当然,协议中更多的是定义了一些必须不cache的反例:

  1. 带cookie情况
  2. 没有body情况
  3. 返回状态码>399情况,返回状态码非标准情况
  4. 。。。

当然,这些由RFC里的Must、May、Must Not组成的声明,就是协议兼容性测试用例中必须重点关注的点,目前整个行业中,协议兼容性做的最专业的是Co-Advisor公司为w3c做的平台,测试用例是最全的,有收费模式,也有免费的可以在线使用,包括ATS、squid都使用这个系统在做协议性的完善。在阿里的测试团队的case沉淀中,我们也对测试协议兼容性、TS的功能模块测试中,沉淀出了Macaroon测试框架,并积累了相当可观的测试用例,当然这些是免费的。

什么应该cache,第一级

上面我们说过,默认下ATS是否缓存,都是遵守源站的返回结果控制的,而最最最基础的控制就是使用返回的header来直接控制,让我们来看看其中最最基础的情况:

  1. cache的最基本控制,控制cache的前提条件:

    records.config中有如下配置:

       # required headers: three options:
       #   0 - No required headers to make document cachable
       #   1 - "Last-Modified:", "Expires:", or "Cache-Control: max-age" required
       #   2 - explicit lifetime required, "Expires:" or "Cache-Control: max-age"
    CONFIG proxy.config.http.cache.required_headers INT 2
    

    这个配置 proxy.config.http.cache.required_headers 指明了cache需要的明确的header是什么

    • 0 要求最松,不须指定任何头,我们都会cache住他们(这个参数一般会配合后面讲到的模糊缓存策略使用),cache效率最高,当然风险也最大

      如果你希望最大量的缓存住所有的内容,这个参数是必需的。正向代理推荐,当然必需关注风险。

    • 1 需要带有:Last-Modified: Expires: Cache-Control: max-age 三个header头中最少一个。这个模式下,允许一个静态文件只带:Last-Modified: 头就可以缓存的在ATS中。

      我个人建议使用这个参数,配合模糊缓存策略,比较符合普通网站以静态文件为主的CDN使用方式。

    • 2 必需主动明确指定缓存时间,即带有 Expires: Cache-Control: max-age之一,这样cache的缓存时间是明确的。这是默认模式,也是最严格的模式。

      这个模式是最保险的,从做网站CDN的角度,从默认安全配置一步步来是比较靠谱的,除非你非常了解你的网站的内容。

  2. cache中,很可能会存有动态的内容,其中动态的内容又有些是跟用户有关系的,这些内容中有部分是带cookie的,而这部分跟用户有关的带cookie的数据,是cache中最最最需要特殊的对待的数据之一,这涉及到用户数据的安全问题,如果缓存了不应该缓存的数据,将会引起很大的灾难。

    records.config中有如下配置:

       # cache responses to cookies has 5 options:
       #   0 - do not cache any responses to cookies
       #   1 - cache for any content-type
       #   2 - cache only for image types
       #   3 - cache for all but text content-types
       #   4 - cache for all but text content-types except OS response
       #       without "Set-Cookie" or with "Cache-Control: public"
       # See also cache-responses-to-cookies in cache.config.
    CONFIG proxy.config.http.cache.cache_responses_to_cookies INT 1
    

    配置项 proxy.config.http.cache.cache_responses_to_cookies 决定是否缓存带cookie的源服务器返回结果:

    • 0 不缓存任何带cookie的源服务器返回结果

      这种情况下是最最最安全的设计。由于许多上CDN的网站域名使用很混乱,通常动态内容和静态内容混合跑,这样动态内容引入的cookie会挂在这样的域名下,造成域名下的请求都是带cookie的,甚至服务器端会给所有内容Set-Cookie,这种结果就会给ATS的缓存效果造成极大的影响。从大型CDN的运营中,我们强烈推荐使用专用的域名做CDN内容分发,并严格控制cookie的使用,尽量避免在CDN域名上使用cookie。

    • 1 缓存任何结果

      这个配置跟上面的选项正式截然相反,够狠够大胆。坏处自然也就是所有cookie混乱造成的结果的一样啦。但是鉴于cookie的正常使用和非合理使用的情况都是存在的,引起的结果是不可预料的。如果缓存的都是图片啥的,没啥大不了的问题,如果是html等内容,可能就会出现登录串号等诡异故障。

    • 2 只缓存图片类型的结果

      相对来说,很少有服务器队图片类型的返回结果set cookie,所以只对图片类型的数据忽略cookie的影响是比较安全的一个做法,这是很保守的一个配置。推荐入门使用。

    • 3 缓存除了text类型的所有结果

      相比上面的保守的只缓存图片类项,这里稍微激进的缓存除了text(html)的内容,这样可以缓存的内容范围就比较的大了,相对缓存的效率也就高多了。这种黑名单的机制得需要你自己判断,是否把html文件隔离就安全了呢???

    • 4 缓存所有的非text类型的返回结果,以及不带 Set-Cookie 头或带 Cache-Control: public的text类型的源服务器返回结果

      相对上面这这个稍微激进的方式,我们更准确的把更多的可以比较安全cache的text类型(html)数据包含进来,更激进当然效率更好啦。相对来说,这个的安全性和上面这个也差不多,推荐进阶用户使用。

    问题是,很多网站并不是非常清楚cookie会带来什么,什么时候该set cookie,什么时候不应该set cookie,这就造成很多很多困扰,尤其是你的商业CDN接入客户网站的时候,你需要跟客户做很多的沟通,梳理其中的问题,在尽量控制源的情况下,配合好。

    cache.config中的 cache-responses-to-cookies 指令,具有同样的效果,并具有更自由的控制策略组合,如对目录、正则表达式、后缀等。建议对cache规则有高需求的用户使用。

第二级,什么可以cache?

上面第一级中,对什么应该cache做了最基础的说明,ATS认为服务器明确指令的可以cache的内容都是应该要缓存下来的。那么除了这些之外,还有什么是可以cache的呢?

ATS系统设计者认为,在缓存设计的时候,需要遵循RFC的约定,也需要给予一定的自由度以突破RFC的限制,因此ATS设计了很多用来影响这些的控制点,下面我们以什么可以cache为主线来说明ATS的独特设计。当然,我们说的都是第一级之外的话题。

  1. 没有内容的返回,也可以缓存。

    按照RFC规定,只有header而没有其他内容的返回结果,cache服务器不能缓存。而我们运营大规模CDN中,只有header的情况还是很多的:

    • 针对IMS请求的304返回
    • 确实没有其他内容的返回,多数是应用需要啊等等,这种情况为数不少。比如用来做统计等的一个没有返回结果的URL。

    如果全部放弃对这些没有内容的返回数据,则会影响命中率以及回源连接数量、源服务器的压力等,这也不是一个大型的CDN希望看到的。因此ATS设计了一个 proxy.config.http.cache.allow_empty_doc 这个参数,默认为0,设置为1可以启动对没有正式返回内容的结果进行缓存。当然,启用这个参数也不能说明,所有的没正式内容的结果都会被缓存,真正是不是缓存也需要看其他条件,比如第一级中说的一些规则,以及后面的其他条件。

  2. 错误的结果,也可以缓存。

    错误的结果缓存好吗??这个问题一直是很多人讨论的话题,多数这种有没有必要、有没有意义的讨论都会走到一句话:It depends。我们这里也是一样的,因此也就是又多了一个records参数 proxy.config.http.negative_caching_enabled

    我们建议,慎重考虑启用这个缓存机制:

    • 建议设置一个很小的时间给 negative_caching_lifetime 参数以制约错误引入的负面影响。
    • 需要有反制的机制,如大规模刷新(revalidate)内容的能力。

    用好这个参数,对源站大规模故障行为等极端情况非常有帮助。当然,如果用错了,那会更悲剧。

  3. range的内容也可以缓存。

    按照RFC规定,Range回源的请求,返回的内容是不能缓存的。但是,像ATS这样的项目,必然会对这个很影响命中率的问题发起挑战。在TS核心里,跟range有关系的就两个参数:proxy.config.http.cache.range.lookupproxy.config.http.cache.range.write,这两个参数默认都是开启的哦。当然,这两个参数一个控制range的请求查不查cache,另一个控制range的请求是否能够作为可cache的请求。貌似跟大家没啥关系啊,但没有他们俩,这个世界就更惨了。要怪就得怪RFC对range的处理简直是个灾难,比如用户端发的是range,源服务器完全可以给你个200的结果啊。

    其实,最最最有用的,不是这两个参数决定的。而是类似分片缓存的这种效果,这个目前可是各个公司的机密哦:总体需求可以参照 ATS wiki里讲的来做吧。

  4. 客户端带no-cache的也可以缓存

    客户端带no-cache的情况,多数是页面强制刷新的情况,这种情况下,如果全部回源做IMS刷新的话,事实上开销是不小的。在大规模CDN里,控制内容的刷新,一定是需要一个更严格的机制,而避免用户的请求能够直接刷新到源站去。因此ATS对客户端带 no-cache 的情况,有个参数 proxy.config.http.cache.ignore_client_no_cache 可以控制。启用后,客户端的no-cache对ATS是无效的。

    非常建议这个配置启用,当然,更建议更高效的管理cache内容,回头我们再开单独的话题讨论如何提高内容管理的可控性。

  5. 服务器端带no-cache的也可以缓存

    OK,我们已经知道客户端的no-cache是最好忽略掉啦,那么服务器端呢?ATS在做配置的时候,很多都是服务器、客户端对称设计,所以ATS对服务器端也有一个忽略 no-cache 的选项 proxy.config.http.cache.ignore_server_no_cache,当然这个也就是忽略服务器端的no-cache啦。

    作为CDN来说,忽略server端对cache的控制绝对不是个好主意,所以这个参数默认是关闭的。我们相信,你已经明白了其中的道理,才启用这个参数的。

  6. 客户端带cc-maxage=0的也可以缓存

    http/1.1以后,客户端刷新的情况下,浏览器多数是发送一个 cc-maxage=0 的控制来做强制cache刷新,有的浏览器甚至把这个参数和 no-cache 并用。我们对待这个参数,应该会需要像客户端的 no-cache 一样的协调处理。

  7. 关于IMS请求

    关于IMS的请求,源服务器端会有两种情况:

    • 源服务器数据没改变,返回304的结果
    • 源服务器数据有改变,返回200的结果

    在繁忙的CDN服务器中,IMS的请求,或者说cache端的304的结果,数量是相当可观的。把这部分请求缓存起来,能够显著的提升cache的效率。控制这里的关键是上面第一条。

    当然,如果把一些客户端的 no-cache 等转为回源做IMS请求,是否可以极大的减少不必要的回源带宽消耗呢?毕竟一个是要传内容的,另一个是要传数据的,差距是很大的。ATS有一个参数,可以打开这个功能 proxy.config.http.cache.ims_on_client_no_cache

    这个看起来更像是一个中间状态的解决方案。

总之,ATS在可以cache方面,已经扩展的相当的宽泛了。要使用好这些功能,才能够发挥好ATS的效率。

第三级,什么必须cache

我们做cache,做CDN,就是解决两个经典问题:提高用户感受、降低成本。这两个经典问题,无论怎么优化,都会落到提高cache命中率,提高cache使用效率上来。这就是

  1. 大规模流量的内容
  2. 大规模请求量的内容

经典问题经典解决,从miss的日志中,分析miss的问题,是最最最有效的快速解决方案。如何发现ATS为什么会miss呢?不外乎cache的控制(源端、TS端)或cache的存储(空间、条目等)

例如:
ATS会对不同的Accept-Encoding头进行全字符串匹配,才会返回给用户同样的结果。然而,我们的客户端发出来的AE头,没有一千也有八百,这就造成很多很多存储空间的浪费以及匹配不命中,甚至会直接达到最大副本数目CONFIG proxy.config.cache.limits.http.max_alts INT 5被默认设置为5,这样,如果有新的副本由于AE头不匹配,就会顶掉已经存储的5个中的一个,缓存进入cache系统。而越多的AE组合,就会造成越多的替换和miss。

怎么样分析这类问题呢??

cache的问题都可以用http_ui的cache检查工具来看,这个web界面的工具,可以直接给你列出cache的所有副本的详细请求头、返回头、缓存body数据大小、创建修改时间等等非常detail的信息。配合日志miss分析确定相关URL后,如果是cache的问题,就可以用这个号称瑞士军刀的http_ui工具来分析啦。

如何解决问题?

ATS自然已经想到这个问题啦,目前推荐的解决方案就是简单粗暴的模式,我们都知道目前最通用的AE方式是gzip,那把AE简化成要么gzip,要么不gzip就结了吧:

CONFIG proxy.config.http.normalize_ae_gzip INT 1

当然,如果你有更多的AE方法需要保留,可以再自己写插件来完成这个过滤。

ATS已经就这些基础的方面,做了很多的选项:

proxy.config.http.cache.ignore_accept_mismatch
proxy.config.http.cache.ignore_accept_language_mismatch
proxy.config.http.cache.ignore_accept_encoding_mismatch
proxy.config.http.cache.ignore_accept_charset_mismatch

这些都是可以让你简单粗暴有效果的搞定这些恼人的问题,当然,后果自己要清楚哦。

anyway,拿出你的所有本领,分析miss的情况,并搞定它们。当然如果图省事,交给专业团队搞吧。

第四级,什么能cache

这个话题是一个吵架的好题目,较真的不较真的都可以吵一架,我们只就ATS自身来说吧

  1. 什么都能cache

    • 源端并不是都有很清楚的控制,甚至某些时候源端改起来很麻烦,怎么办??

      当然,这种情况最好的解决办法是跟源端做沟通,高效率的CDN架构,会把动态、静态内容做好分割,哪怕是目录的分割都会让ATS系统做cache很方便。

    • 源端就是不让cache,而你知道它们应该被cache又怎么办?

      用强的ATS也可以啊,cache.config里加个强制的控制就好了。

  2. 即使TS核心不能,你也可以自己写插件让它能

    • Range回源的,也可以cache,你可以写插件实现如下功能:

      1. 把Range头去掉再回源
      2. 把Range头去掉回源,然后transform切片给客户端
      3. 更高大上的是Range切片回源,Range切片给客户端,还保存。
    • 流媒体,我说的是真正的流媒体,如rtmp rtsp rtp协议等。想当初流媒体解决方案是ATS独一无二的哦

    • p2p:p2p也可以用protocol插件来搞定,并且可以使用ATS的存储。

最后强调,什么不能cache

  1. 涉及到用户的不同数据的
  2. 会影响用户使用感受的
  3. 有法律风险的

其实,就是会给你造成麻烦的,做cache就是要自重啊,把自己弄到坑里去是最不明智的了。

  1. nbox
    2014年7月11日19:41 | #1

    大师布道了!

  2. Aries
    2015年11月21日01:54 | #2

    博主你好,

    我最近在解决国内用户访问国外网站延时的问题。
    现在我有一个服务器在德国,国内有一个ATS服务器,配置大概是10G disc cache+1.5G memory cache,现在cache hit ratio大概是38%。

    record.config里面我已经设置了
    CONFIG proxy.config.http.normalize_ae_gzip INT 1
    CONFIG proxy.config.http.cache.ignore_accept_mismatch INT 1
    CONFIG proxy.config.http.cache.ignore_accept_language_mismatch INT 1
    CONFIG proxy.config.http.cache.ignore_accept_encoding_mismatch INT 1
    CONFIG proxy.config.http.cache.ignore_accept_charset_mismatch INT 1

    但是当我通过浏览器打开cache state(通过开启http_ui_enabled)搜索我要查看的url,发现这个url有20个alternative,我把max_alts设置成20,但是每个alternative的request header除了我上面record.config里面设置忽略掉的以为,就只有主要是User-Agent不同了。

    是不是ATS会对每个不同的User-Agent缓存一份文件,这样下来不有太多的同一份文件,多个copy了?

    能不能通过设置让ATS忽略User-Agent或者其他的Request Header,让每个文件都之保留一份alternative,因为我网站的99%的内容都是可以缓存的。

    谢谢。

  1. 本文目前尚无任何 trackbacks 和 pingbacks.