Varnish 哈希函数服务于来自同一缓存的 SSR 和 AJAX 调用
Varnish Hash function to serve both SSR and AJAX call from the same cache
我们正在使用 Varnish 缓存代理(在 docker 容器中)来为 SSR 和 AJAX 请求提供服务。目标是让共享缓存(用于注销)用户独立于他们访问数据的方式。选项是 Nuxt (SSR) 或浏览器中的 AJAX 调用(通过 Axios)。浏览器向 https://api.foobar.tld/levels 发出请求,而 SSR 向位于 http://api-foobar-cache-proxy/levels 的内部 docker 容器发出请求。
这主要是有效的,除非它不起作用(案例 4,在日志中)。问题是为什么?
Varnish 使用以下(自定义)哈希函数:
sub vcl_hash {
hash_data(req.url);
std.log("X-DEBUG-url:" + req.url);
if (req.http.Origin ~ "foobar") {
hash_data("HOSTfoobar");
std.log("X-DEBUG-host:1-HOSTfoobar");
} elseif (req.http.host ~ "foobar") {
hash_data("HOSTfoobar");
std.log("X-DEBUG-host:2-HOSTfoobar");
}
if (req.http.Locale) {
hash_data(req.http.Locale);
std.log("X-DEBUG-locale:1-" + req.http.Locale);
} else {
hash_data("de");
std.log("X-DEBUG-locale:2-de");
}
return (lookup);
}
调试日志:
varnishncsa -F '"%r" %{Varnish:handling}x %{VCL_Log:X-DEBUG-url}x %{VCL_Log:X-DEBUG-host}x %{VCL_Log:X-DEBUG-locale}x' | grep "/levels"
输出:
1: "GET http://api-foobar-cache-proxy/levels HTTP/1.1" miss /levels 1-HOSTfoobar 1-de // SSR first call (miss, expected, cold cache)
2: "GET http://api-foobar-cache-proxy/levels HTTP/1.1" hit /levels 1-HOSTfoobar 1-de // SSR second call (hit, expected)
3: "OPTIONS https://api.foobar.tld/levels HTTP/1.1" pass /levels 1-HOSTfoobar 2-de // Browser OPTIONS call (miss, expected)
4: "GET https://api.foobar.tld/levels HTTP/1.1" miss /levels 1-HOSTfoobar 1-de // Browser first call (miss, not expected)
5: "OPTIONS https://api.foobar.tld/levels HTTP/1.1" pass /levels 1-HOSTfoobar 2-de // Browser OPTIONS call (miss, expected)
6: "GET https://api.foobar.tld/levels HTTP/1.1" hit /levels 1-HOSTfoobar 1-de // Browser second call (hit, expected)
未达预期:
1: 冷缓存
预计通过:
3、5:OPTIONS不缓存,只GET请求
预期命中率:
2、6:来自缓存
意想不到的小姐:
4:为什么?对于所有这些 3 hash_data
参数,其中:/levels
、HOSTfoobar
和 de
。此外,return (lookup)
应该阻止内置的 vcl_hash
,除非我完全弄错了。
来自 varnishlog
的请求的一些额外调试输出:
比较请求的 varnishlog
。完整的日志可以在这里找到 https://0bin.net/paste/2UYa-YSr#ykSOg11iJxJXA-CsUiK4es1gGekUDN4VL3wqVA9Jqdv,相关部分(?):
请求 1:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- VCL_call MISS
- ReqHeader x-cache: miss
- VCL_return fetch
- Link bereq 32771 fetch
[...]
请求 2:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- Hit 32771 3585.968366 3600.000000 0.000000
- VCL_call HIT
[...]
请求 4:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- VCL_call MISS
- ReqHeader x-cache: miss
- VCL_return fetch
- Link bereq 98318 fetch
[...]
请求 6:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- Timestamp Waitinglist: 1636723569.802992 0.183061 0.183061
- Hit 98318 3600.182590 3600.000000 0.000000
- VCL_call HIT
[...]
所以,结果和往常一样,电脑没有问题,是用户的问题。在后端我使用 API Platform,它可以响应不同的内容类型。前任。如果您在浏览器中请求 /levels
,它将提供 Swagger UI,但是如果您使用 Accept: application/json
请求,它将提供 JSON 版本。将 SSR(模仿 cURL)请求上的接受 header 从 */*
更改为 application/json, */*
就成功了。
我们正在使用 Varnish 缓存代理(在 docker 容器中)来为 SSR 和 AJAX 请求提供服务。目标是让共享缓存(用于注销)用户独立于他们访问数据的方式。选项是 Nuxt (SSR) 或浏览器中的 AJAX 调用(通过 Axios)。浏览器向 https://api.foobar.tld/levels 发出请求,而 SSR 向位于 http://api-foobar-cache-proxy/levels 的内部 docker 容器发出请求。 这主要是有效的,除非它不起作用(案例 4,在日志中)。问题是为什么?
Varnish 使用以下(自定义)哈希函数:
sub vcl_hash {
hash_data(req.url);
std.log("X-DEBUG-url:" + req.url);
if (req.http.Origin ~ "foobar") {
hash_data("HOSTfoobar");
std.log("X-DEBUG-host:1-HOSTfoobar");
} elseif (req.http.host ~ "foobar") {
hash_data("HOSTfoobar");
std.log("X-DEBUG-host:2-HOSTfoobar");
}
if (req.http.Locale) {
hash_data(req.http.Locale);
std.log("X-DEBUG-locale:1-" + req.http.Locale);
} else {
hash_data("de");
std.log("X-DEBUG-locale:2-de");
}
return (lookup);
}
调试日志:
varnishncsa -F '"%r" %{Varnish:handling}x %{VCL_Log:X-DEBUG-url}x %{VCL_Log:X-DEBUG-host}x %{VCL_Log:X-DEBUG-locale}x' | grep "/levels"
输出:
1: "GET http://api-foobar-cache-proxy/levels HTTP/1.1" miss /levels 1-HOSTfoobar 1-de // SSR first call (miss, expected, cold cache)
2: "GET http://api-foobar-cache-proxy/levels HTTP/1.1" hit /levels 1-HOSTfoobar 1-de // SSR second call (hit, expected)
3: "OPTIONS https://api.foobar.tld/levels HTTP/1.1" pass /levels 1-HOSTfoobar 2-de // Browser OPTIONS call (miss, expected)
4: "GET https://api.foobar.tld/levels HTTP/1.1" miss /levels 1-HOSTfoobar 1-de // Browser first call (miss, not expected)
5: "OPTIONS https://api.foobar.tld/levels HTTP/1.1" pass /levels 1-HOSTfoobar 2-de // Browser OPTIONS call (miss, expected)
6: "GET https://api.foobar.tld/levels HTTP/1.1" hit /levels 1-HOSTfoobar 1-de // Browser second call (hit, expected)
未达预期: 1: 冷缓存
预计通过: 3、5:OPTIONS不缓存,只GET请求
预期命中率: 2、6:来自缓存
意想不到的小姐:
4:为什么?对于所有这些 3 hash_data
参数,其中:/levels
、HOSTfoobar
和 de
。此外,return (lookup)
应该阻止内置的 vcl_hash
,除非我完全弄错了。
来自 varnishlog
的请求的一些额外调试输出:
比较请求的 varnishlog
。完整的日志可以在这里找到 https://0bin.net/paste/2UYa-YSr#ykSOg11iJxJXA-CsUiK4es1gGekUDN4VL3wqVA9Jqdv,相关部分(?):
请求 1:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- VCL_call MISS
- ReqHeader x-cache: miss
- VCL_return fetch
- Link bereq 32771 fetch
[...]
请求 2:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- Hit 32771 3585.968366 3600.000000 0.000000
- VCL_call HIT
[...]
请求 4:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- VCL_call MISS
- ReqHeader x-cache: miss
- VCL_return fetch
- Link bereq 98318 fetch
[...]
请求 6:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- Timestamp Waitinglist: 1636723569.802992 0.183061 0.183061
- Hit 98318 3600.182590 3600.000000 0.000000
- VCL_call HIT
[...]
所以,结果和往常一样,电脑没有问题,是用户的问题。在后端我使用 API Platform,它可以响应不同的内容类型。前任。如果您在浏览器中请求 /levels
,它将提供 Swagger UI,但是如果您使用 Accept: application/json
请求,它将提供 JSON 版本。将 SSR(模仿 cURL)请求上的接受 header 从 */*
更改为 application/json, */*
就成功了。