根据 cookie 变化而不会产生重复的缓存条目
Vary based on cookie without producing duplicate cache entries
我正在开发一个 multi-tenant 平台,我们的客户可以在该平台上创建在线商店。商店可能同时销售多种货币的产品,例如欧元和美元。
由于所显示产品的价格因货币而异,我希望为欧元和美元缓存页面。
让它工作的初始部分相当容易,但我遇到了一个不希望的副作用。
sub vcl_recv {
if (req.http.cookie) {
cookie.parse(req.http.cookie);
// If the user has a `currency` cookie, set it as a header
set req.http.x-currency = cookie.get("currency");
}
...
}
sub vcl_hash {
hash_data(req.http.x-currency);
}
我的后端识别使用此 header 或不使用它来呈现正确的输出,然后 Varnish 存储结果。如果请求没有这个header,服务器发送一个Set-Cookie
header,它会告诉浏览器用商店的默认货币创建一个cookie。
我的问题源于这样一个事实,即我事先无法知道商店的默认货币(在我们的例子中是欧元或美元),因为店主可以 add/remove 他们动态地。
因此,在对 /homepage
端点的第一个请求中,用户不会有 currency
cookie,因此它的值将为 '',这将在 hash_data
方法。
服务器识别出客户端没有货币cookie,所以它设置了一个Set-Cookie
header,当页面命中浏览器时,客户端就会有cookie。
目前,我们有 /homepage
的缓存条目,没有 currency
cookie。
客户点击刷新,请求到达 Varnish。
这一次,有一个currency
cookie,在hash_data
函数中使用,但它产生了不同的密钥,所以它再次命中后端,但输出将是相同(显然,Varnish 并不知道)。
/homepage
url 有两个关联的缓存条目,它们具有相同的内容。
有没有我可以采用的替代方法来解决这个问题,或者某种修复方法?
我最初的思路是:
进入 vcl_backend_response
子例程并检查请求。如果请求缺少 cookie,则 beresp
object 将在其 Set-Header
中包含商店的默认货币。我可以使用它来创建 2 个不同的缓存键,它们指向相同的缓存条目 - /homepage + ''
用于空 cookie 和 /homepage + 'EUR'
.
这在技术上是不可能的,但它说明了似乎可以解决我的问题。
为简单起见,我没有提供 100% 的 vcl 配置,但我使用默认 vcl 作为模板为 vcl_recv
和 vcl_backend_response
创建自定义配置。我知道 cookie 意味着个性化内容,我不应该缓存它,但这种情况下的个性化对这个用户来说并不是唯一的,所以我做了一个例外。
编辑
www.mystore.com/en/ - 默认货币为美元
sub vcl_hash {
if(req.url !~ "^/(contact|sitemap)") {
hash_data(req.http.x-currency);
}
}
目前缓存中没有任何内容
- 用户第一次访问
homepage
,他没有任何 cookies
- Varnish 根据
http.x-currency
生成一个散列,该散列为空。结果没中。
- varnish打到后端,后端看到缺少
x-currency
header,所以设置了一个Set-Cookieheader,设置cookie为USD
- Varnish 接收响应,缓存它,并将它发送回客户端
- 同一用户在同一页面上点击刷新
- Varnish 根据
http.x-currency
生成哈希,现在是 USD(上次是空的),导致缓存未命中,再次
- Varnish 去后端,后端returns 完全相同的响应,因为没有
x-currency
或x-currency
= USD 对后端来说是相同的
- Varnish 接收响应,缓存它并returns它到客户端
主页路由现已完全缓存。无论某人是否使用 currency=USD
cookie 进行访问,他都会收到缓存的响应。但是,缓存寄存器中有两个条目,一个用于空 currency
cookie,另一个用于 currency=USD
cookie,并且两者的结果相同。
问题源于这样一个事实,当一个请求到达并且它没有 currency
cookie 时,如果没有后端的帮助,我没有一个可预测的方法来计算它的值.
在我看来,好像我只能忍受这个。
据我了解,您只想为包含不同货币的页面创建缓存变体。根据您提供的信息,我假设主页在内容方面没有差异,不需要变化。
URL匹配
您可以匹配某些不需要变体的 URL 模式并有条件地执行变体。
这是一个例子:
sub vcl_hash {
if(req.url !~ "^/(homepage|contact|sitemap)") {
hash_data(req.http.x-currency);
}
}
这是一个过于简单化的示例,但我希望您理解可以有条件地进行更改。使用包含或排除模式。
发送一个变化header
您还可以通过发送以下 Vary
响应 header 来管理应用程序中的条件变化方面:
Vary: x-currency
通过这样做,您可以在应用程序中管理变体,而不依赖于 sub vcl_hash
中的 hash_data()
。
请记住,x-currency
请求 header 需要发送到应用程序。这不是真正的问题,因为您已经在 vcl_recv
.
中设置了这个 header
It is important to strip off this part of the Vary
header in vcl_deliver
because the client has no awareness of this request header.
主页问题的重复键
在你上面的(更新的)问题以及下面的评论中,你谈到了假设的 /homepage
object 基于 x-currency
header.
这对您来说应该不是问题。我注意到您了解 Varnish 中散列的工作原理。
我上面提到的 2 个解决方案(URL 匹配和变化)解释了如何有条件地 扩展哈希。 有条件地 一词在这里非常重要。
如果 /homepage
路由产生完全相同的 about 而不管 x-currency
值,这意味着 x-currency
不应该是散列的一部分。这也意味着 URL 和 host header 将构成散列的基础。
通过不在 hash_data()
中添加 x-currency
或作为 Vary
header 的一部分,/homepage
将只有一个版本。
您表示 Vary: x-currency
是您的首选解决方案。我建议您只为每种货币具有不同输出的页面设置它。
我的印象是你的问题将通过有条件地改变货币来解决。
Set-Cookieheader呢?
另一个重要的评论是关于 return Set-Cookie
header 如果未设置货币的页面。
Varnish 的标准行为将导致 so-called Hit-For-Miss.
这意味着 object 没有存储在缓存中,因为您不想为每个人缓存 Set-Cookie
header。
在接下来的 2 分钟内,对该资源的所有请求都将绕过缓存,除非下一个响应变为可缓存。
在您的情况下,对 /homepage
的第二个请求将变得可缓存,因为响应将不再包含 Set-Cookie
.
在命中率方面的结果是,由于 Set-Cookie
.
,每个用户的第一个请求都将是缓存未命中
请记住这一点。
就我个人而言,我不会担心这一点,但如果你这样做,你实际上可以剥离 beresp.http.Set-Cookie
以使页面可缓存并自己在 vcl_deliver
.[=37 中设置 cookie =]
当然,您需要访问决定 EUR 与 USD 的逻辑才能正确设置 cookie 值。
我正在开发一个 multi-tenant 平台,我们的客户可以在该平台上创建在线商店。商店可能同时销售多种货币的产品,例如欧元和美元。
由于所显示产品的价格因货币而异,我希望为欧元和美元缓存页面。
让它工作的初始部分相当容易,但我遇到了一个不希望的副作用。
sub vcl_recv {
if (req.http.cookie) {
cookie.parse(req.http.cookie);
// If the user has a `currency` cookie, set it as a header
set req.http.x-currency = cookie.get("currency");
}
...
}
sub vcl_hash {
hash_data(req.http.x-currency);
}
我的后端识别使用此 header 或不使用它来呈现正确的输出,然后 Varnish 存储结果。如果请求没有这个header,服务器发送一个Set-Cookie
header,它会告诉浏览器用商店的默认货币创建一个cookie。
我的问题源于这样一个事实,即我事先无法知道商店的默认货币(在我们的例子中是欧元或美元),因为店主可以 add/remove 他们动态地。
因此,在对 /homepage
端点的第一个请求中,用户不会有 currency
cookie,因此它的值将为 '',这将在 hash_data
方法。
服务器识别出客户端没有货币cookie,所以它设置了一个Set-Cookie
header,当页面命中浏览器时,客户端就会有cookie。
目前,我们有 /homepage
的缓存条目,没有 currency
cookie。
客户点击刷新,请求到达 Varnish。
这一次,有一个currency
cookie,在hash_data
函数中使用,但它产生了不同的密钥,所以它再次命中后端,但输出将是相同(显然,Varnish 并不知道)。
/homepage
url 有两个关联的缓存条目,它们具有相同的内容。
有没有我可以采用的替代方法来解决这个问题,或者某种修复方法?
我最初的思路是:
进入 vcl_backend_response
子例程并检查请求。如果请求缺少 cookie,则 beresp
object 将在其 Set-Header
中包含商店的默认货币。我可以使用它来创建 2 个不同的缓存键,它们指向相同的缓存条目 - /homepage + ''
用于空 cookie 和 /homepage + 'EUR'
.
这在技术上是不可能的,但它说明了似乎可以解决我的问题。
为简单起见,我没有提供 100% 的 vcl 配置,但我使用默认 vcl 作为模板为 vcl_recv
和 vcl_backend_response
创建自定义配置。我知道 cookie 意味着个性化内容,我不应该缓存它,但这种情况下的个性化对这个用户来说并不是唯一的,所以我做了一个例外。
编辑
www.mystore.com/en/ - 默认货币为美元
sub vcl_hash {
if(req.url !~ "^/(contact|sitemap)") {
hash_data(req.http.x-currency);
}
}
目前缓存中没有任何内容
- 用户第一次访问
homepage
,他没有任何 cookies - Varnish 根据
http.x-currency
生成一个散列,该散列为空。结果没中。 - varnish打到后端,后端看到缺少
x-currency
header,所以设置了一个Set-Cookieheader,设置cookie为USD - Varnish 接收响应,缓存它,并将它发送回客户端
- 同一用户在同一页面上点击刷新
- Varnish 根据
http.x-currency
生成哈希,现在是 USD(上次是空的),导致缓存未命中,再次 - Varnish 去后端,后端returns 完全相同的响应,因为没有
x-currency
或x-currency
= USD 对后端来说是相同的 - Varnish 接收响应,缓存它并returns它到客户端
主页路由现已完全缓存。无论某人是否使用 currency=USD
cookie 进行访问,他都会收到缓存的响应。但是,缓存寄存器中有两个条目,一个用于空 currency
cookie,另一个用于 currency=USD
cookie,并且两者的结果相同。
问题源于这样一个事实,当一个请求到达并且它没有 currency
cookie 时,如果没有后端的帮助,我没有一个可预测的方法来计算它的值.
在我看来,好像我只能忍受这个。
据我了解,您只想为包含不同货币的页面创建缓存变体。根据您提供的信息,我假设主页在内容方面没有差异,不需要变化。
URL匹配
您可以匹配某些不需要变体的 URL 模式并有条件地执行变体。
这是一个例子:
sub vcl_hash {
if(req.url !~ "^/(homepage|contact|sitemap)") {
hash_data(req.http.x-currency);
}
}
这是一个过于简单化的示例,但我希望您理解可以有条件地进行更改。使用包含或排除模式。
发送一个变化header
您还可以通过发送以下 Vary
响应 header 来管理应用程序中的条件变化方面:
Vary: x-currency
通过这样做,您可以在应用程序中管理变体,而不依赖于 sub vcl_hash
中的 hash_data()
。
请记住,x-currency
请求 header 需要发送到应用程序。这不是真正的问题,因为您已经在 vcl_recv
.
It is important to strip off this part of the
Vary
header invcl_deliver
because the client has no awareness of this request header.
主页问题的重复键
在你上面的(更新的)问题以及下面的评论中,你谈到了假设的 /homepage
object 基于 x-currency
header.
这对您来说应该不是问题。我注意到您了解 Varnish 中散列的工作原理。
我上面提到的 2 个解决方案(URL 匹配和变化)解释了如何有条件地 扩展哈希。 有条件地 一词在这里非常重要。
如果 /homepage
路由产生完全相同的 about 而不管 x-currency
值,这意味着 x-currency
不应该是散列的一部分。这也意味着 URL 和 host header 将构成散列的基础。
通过不在 hash_data()
中添加 x-currency
或作为 Vary
header 的一部分,/homepage
将只有一个版本。
您表示 Vary: x-currency
是您的首选解决方案。我建议您只为每种货币具有不同输出的页面设置它。
我的印象是你的问题将通过有条件地改变货币来解决。
Set-Cookieheader呢?
另一个重要的评论是关于 return Set-Cookie
header 如果未设置货币的页面。
Varnish 的标准行为将导致 so-called Hit-For-Miss.
这意味着 object 没有存储在缓存中,因为您不想为每个人缓存 Set-Cookie
header。
在接下来的 2 分钟内,对该资源的所有请求都将绕过缓存,除非下一个响应变为可缓存。
在您的情况下,对 /homepage
的第二个请求将变得可缓存,因为响应将不再包含 Set-Cookie
.
在命中率方面的结果是,由于 Set-Cookie
.
请记住这一点。
就我个人而言,我不会担心这一点,但如果你这样做,你实际上可以剥离 beresp.http.Set-Cookie
以使页面可缓存并自己在 vcl_deliver
.[=37 中设置 cookie =]
当然,您需要访问决定 EUR 与 USD 的逻辑才能正确设置 cookie 值。