我有一个 varnish+nginx 前面的 Ruby on Rails 应用程序。由于大多数站点内容都是静态的,除非您是登录用户,因此我想在用户注销时使用清漆大量缓存站点,但仅在用户登录时缓存静态资产。
当用户登录时,他们的 Cookie: 标头中将包含 cookie 'user_credentials',此外,我需要跳过 /login 和 /sessions 上的缓存,以便用户首先获得他们的 'user_credentials' cookie .
默认情况下,Rails 不设置缓存友好的 Cache-control 标头,但我的应用程序在用户未登录时设置了“public,s-max-age=60”标头。Nginx 设置为返回“远期”到期标头对于所有静态资产。
我目前的配置是在登录时完全绕过所有内容的缓存,包括静态资产——并且在注销时为所有内容返回缓存 MISS。我花了几个小时在圈子里转,这是我当前的 default.vcl
director rails_director round-robin {
{
.backend = {
.host = "xxx.xxx.xxx.xxx";
.port = "http";
.probe = {
.url = "/lbcheck/lbuptest";
.timeout = 0.3 s;
.window = 8;
.threshold = 3;
}
}
}
}
sub vcl_recv {
if (req.url ~ "^/login") {
pipe;
}
if (req.url ~ "^/sessions") {
pipe;
}
# The regex used here matches the standard rails cache buster urls
# e.g. /images/an-image.png?1234567
if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
unset req.http.cookie;
lookup;
} else {
if (req.http.cookie ~ "user_credentials") {
pipe;
}
}
# Only cache GET and HEAD requests
if (req.request != "GET" && req.request != "HEAD") {
pipe;
}
}
sub vcl_fetch {
if (req.url ~ "^/login") {
pass;
}
if (req.url ~ "^/sessions") {
pass;
}
if (req.http.cookie ~ "user_credentials") {
pass;
} else {
unset req.http.Set-Cookie;
}
# cache CSS and JS files
if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
unset req.http.Set-Cookie;
}
if (obj.status >=400 && obj.status <500) {
error 404 "File not found";
}
if (obj.status >=500 && obj.status <600) {
error 503 "File is Temporarily Unavailable";
}
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
}
好的,最后我设法使用以下 vcl 文件解决了这个问题。请注意,我添加了一些额外的位以在后端死亡时允许缓存过期宽限期。
似乎我的主要失败是
unset req.http.Set-Cookie;
在我应该unset obj.http.Set-Cookie;
在该vcl_fetch
部分中使用时使用。(obj
在 vcl_fetch 和req
vcl_recv 部分)。我无法发表评论,所以我将其发布为答案。
注意:从 2.1.0 开始,obj.* 在 vcl_fetch 中被称为 beresp.*,而 obj.* 现在是只读的。
这些似乎也更好地放置在 vcl_recv 而不是 vcl_fetch 中:
最后,在你的后端定义中,我会添加
调整您允许 nginx/apache 创建的乘客后端的数量。如果你没有设置这个限制,你应该留意你的乘客全局队列(假设你正在使用乘客)。