最近在捣鼓Apache主机时候遇到了一个问题,就是使用腾讯云CDN 进行缓存加速的时候,HTTP 头部报文总是会出现 Vary: Accept-Encoding,User-Agent
这个信息,User-Agent 的导致CDN缓存命中率下降很多。
在而在缓存插件 WP Rocket 中并没有这个 User-Agent
值的设置。通过软件工程师 Mark S. Kolich 的一篇文章,我终于找了 User-Agent
值在哪里。
原文是英文,以下为翻译文章。对 vary进 行了简单介绍。
---
我从来没有过多关注 http 的 vary header。事实上,我非常幸运在过去的很长时间避开了它给我带来的问题,所以就没引起我的关注。但是,如果你最终要配置一个高性能的反向代理服务器,那么理解 vary header 并且它对于你的缓存策略意味着什么事非常有必要的。
下面是一个关于我最近处理关于 squid、apache 的一个有趣的问题,并且这个问题很难找出,竟然是和 vary response header 有关。
本文禁止住转载。任何形式转载请联系作者(时光在路上 www.timezls.com)。时光在路上保留所有权利
1. 关于vary的一些基本信息
流行的缓存代理服务器,像 squid,通常会根据请求的 URI 和 vary response header 的内容产生一个 hash 值。当缓存服务器接收到一个请求的时候,它会根据输入产生一个 hash,之后检查缓存看是否已经有这个资源在硬盘上或者在内存中匹配这个 hash 值。缓存服务器以此来判断命中与否。
而 vary response header 告诉缓存服务器使用什么判断一个请求的资源是 fresh 还是 stale 的,一个简单的 vary header 包括:
- Vary: Accept-Encoding
- Vary: Accept-Encoding, User-Agent
- Vary: X-Some-Custom-Header, Host
- Vary: *
根据 http 标准,vary 的值表明需要哪些 request header 去充分决定一个 response 是否是 fresh 的,缓存服务器是否可以不用重新确认就使用一个 reponse。
本文禁止住转载。任何形式转载请联系作者(时光在路上 www.timezls.com)。时光在路上保留所有权利
2. 缓存遇到的问题
我配置 squid 作为一个轮询的负载均衡服务器和一个反向代理缓存服务器,在 apache 服务器的前面,每个 apache 服务器都运行着我的 web 应用,我严格配置 squid 缓存 .json 文件 24 个小时。
我打开了一个 web 浏览器,我访问了一个我认为已经被缓存的 URL。
- GET /path/big.json HTTP/1.1
- Host: app.kolich.local
- User-Agent: Firefox
- HTTP/1.0 200 OK
- Date: Fri, 24 Sep 2010 23:09:32 GMT
- Content-Type: application/json; charset=UTF-8
- Content-Language: en-US
- Vary: Accept-Encoding, User-Agent
- Age: 1235
- X-Cache: HIT from cache.kolich.local
- X-Cache-Lookup: HIT from cache.kolich.local:80
- Content-Length: 25090
- Connection: close
很好,它已经被缓存了,然后我在另一台机器上打开了第二个 web 浏览器(注:是一个不同类型的浏览器),这一次,注意一下 X-Cache: MISS
- GET /path/big.json HTTP/1.1
- Host: app.kolich.local
- User-Agent: Chrome
- HTTP/1.0 200 OK
- Date: Fri, 24 Sep 2010 23:11:45 GMT
- Content-Type: application/json; charset=UTF-8
- Content-Language: en-US
- Vary: Accept-Encoding, User-Agent
- Age: 4
- X-Cache: MISS from cache.kolich.local
- X-Cache-Lookup: MISS from cache.kolich.local:80
- Content-Length: 25090
- Connection: close
看看它,我请求了一个完全一样的资源,只是从一个不同的浏览器上,现在我看到了一个 MISS。这肯定不是我想看到的结果,我当然需要需要同样的缓存对象而无论到底是谁请求了这个资源。如果就这样放着的话,这个缓存服务器只会是一个每一个浏览器都会有一份拷贝的缓存,而不是一个全局的缓存。
本文禁止全文转载。任何形式转载请联系作者(时光在路上 www.timezls.com) Copyright © 2023. All Rights Reserved
3. 解决方案:检查你的 vary header
观察上面两个请求,注意 User-Agent header 和 Vary header,虽然两个请求都是请求同一个资源,但是 squid 把这个两个请求看做是不同的了,这是怎么发生的呢,我们看一下 Vary header:
本文禁止无授权转载 - 时光在路上 www.timezls.com 保留所有权利
Vary: Accept-Encoding, User-Agent
它告诉 squid 请求的 URI,Accept-Encoding header 和 User-Agent header 应该包括在 hash 值内去决定在缓存上的对象是可用的。很明显的,任何一个(URI, Accept-Encoding, "Firefox")组合的 hash 值和 (URI, Accept-Encoding, "Chrome") 组合产生的 hash 值都是不匹配的,所以 squid 才认为这两个请求是请求不同的内容的。
为了解决这个问题,我找到了这个令人讨厌的、附加在我的 Vary response header 上 的 User-Agent 是从哪来的:原来是在 apache 自带的 mod_deflate 模块。推荐的 mod_deflate 的配置包括:如果一个 response 没有被 mod_deflate 压缩的话 就默认附加 User-Agent 在 Vary header 后面。这是推荐的 apache 配置。关于 mod_deflate的 相关行代码如下:
- SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|ico)$ no-gzip dont-vary
- Header append Vary User-Agent env=!dont-vary
我删除掉了上面的这两行,重启了 apache 然后 squid 会忽略掉请求的浏览器客户端的类型。本质上说,我通过移除 Vary header中的User-Agent告诉squid 不要再去关心用户的浏览器类型,然后问题就解决了。
---
以上是对 Mark S. Kolich 文章的翻译文,我在主机服务器的根目录上找到了 .htaccess 中上面所述的两行语句,删掉,清除 WP Rocket 缓存、刷新CDN缓存。
但事情并没有像预想的那样,结果 Vary 信息结果是这样:
Vary: Accept-Encoding, Cookie, User-Agent
多了一个 Cookie!这也不对啊!Cookie的存在也会导致 CDN 的命中率大幅下降,见我前面写过的文章。必须去掉 Cookie 和 User-Agent 才成功!
本文禁止全文转载。任何形式转载请联系作者(时光在路上 www.timezls.com) Copyright © 2023. All Rights Reserved
解决办法:在网站的根目录(例如 /public_html/)下找到另一个由 WP Rocket “加工”过的 .htaccess 文件,将其中的 Header append Vary: Accept-Encoding
前面添加一行语句:Header unset Vary
,即重置(取消)前面的Vary值,这样做自然把 apache主机自动设置的 Vary 值取消了,转而重新设置下面的 Vary值:Accept-Encoding。—— Cookie 和 User-Agent 都不见了。
经 CDN 加速后,浏览器的头部信息不再有 Cookie, User-Agent,CDN 服务器也不再经常回源,直接命中缓存。如下图所示:
本文禁止全文转载。任何形式转载请联系作者(时光在路上 www.timezls.com) Copyright © 2023. All Rights Reserved
到这里,就解决了由于 HTTP 头部的 Vary 值中含有 User-Agent 而导致 CDN 服务器不断回源、命中率下降的问题。
本文禁止全文转载。任何形式转载请联系作者(时光在路上 www.timezls.com) Copyright © 2023. All Rights Reserved
注:英文原文出自:https://mark.koli.ch/understanding-the-http-vary-header-and-caching-proxies-squid-etc