让清漆从高速缓存中获取旧数据时发送新数据吗?


8

我正在缓存动态生成的页面(PHP-FPM,NGINX),并在它们前面涂上清漆,效果很好。

但是,一旦达到缓存超时,我将看到:

  • 新客户请求页面
  • 清漆识别缓存超时
  • 客户等待
  • 清漆从后端获取新页面
  • varnish将新页面交付给客户端(并且还缓存了页面,用于下一个立即获取它的下一个请求)

我想做的是:

  • 客户要求页面
  • 清漆识别超时
  • 清漆将旧页交付给客户
  • 清漆从后端获取新页面并将其放入缓存

以我为例,过时的信息不是一个大问题,尤其是当我们谈论几分钟后的缓存超时时,这并不是一个好地方。

但是,我不想惩罚用户排队等待,而是立即交付东西。有可能吗?

为了说明这一点,这是对配置为缓存一分钟的服务器运行围攻5分钟的示例输出:

HTTP/1.1,200,  1.97,  12710,/,1,2013-06-24 00:21:06
...
HTTP/1.1,200,  1.88,  12710,/,1,2013-06-24 00:21:20
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:22:08
...
HTTP/1.1,200,  1.89,  12710,/,1,2013-06-24 00:22:22
...
HTTP/1.1,200,  1.94,  12710,/,1,2013-06-24 00:23:10
...
HTTP/1.1,200,  1.91,  12709,/,1,2013-06-24 00:23:23
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:24:12
...

我遗漏了大约数百个正在运行的请求0.02。但是仍然令我担心的是,用户不得不等待将近2秒钟才能获取原始HTML。

我们在这里不能做得更好吗?

(我在缓存时遇到了Varnish发送,听起来很相似,但与我要执行的操作不完全相同。)

Shane Madden的回答包含了解决方案,但我没有立即意识到。我没有在问题中包含另一个细节,因为我认为这不相关,但实际上是相关的。

我当前正在使用的CMS解决方案具有清漆数据库侦听器,因此可以通知清漆禁止内容已更改的页面。它发送了PURGE一些正则表达式来禁止某些页面的请求。

综上所述,有两种情况下我的用户很不幸:

  1. 页面的普通清漆TTL过期
  2. 后端用户更改内容,这会将清除请求发送到清漆

在这两种情况下,我都有“不幸”的用户。在第二种情况下,后端用户通常会在页面更改后检查页面,从而缓解了这种情况。但不一定。

但是,对于第二种情况,我创建了一个解决方案(是的,我意识到这个问题首先是为第一种情况寻求答案……而我本人制定得不好的问题):

我没有发送清除请求,而是使用Shanes建议并调整了VCL,以便我的清漆数据库侦听器可以发送特殊请求以获取hash_always_miss设置为的页面true

使用当前的体系结构,我真的没有做一个真正的异步请求的奢侈,但是借助“ 如何在PHP中发出异步GET请求”的帮助我能够设计一个GET请求来清漆,它不等待页面加载,但是足以触发清漆从后端获取页面并缓存它。

最终结果是数据库侦听器将请求发送给varnish,而当我轮询特定页面时,它从未使我的请求“很不幸”,但是一旦varnish完全从后端获取了页面(范围从300ms到2s),突然在那里。

我还必须找到一种解决方案,当普通TTL用尽时如何避免相同的问题,但是我猜该解决方案也与Shane建议的完全一样:使用wget触发hash_always_miss,我只需要足够聪明即可获取列表我必须刷新的页面数。

Answers:


3

我用来解决此问题的解决方案是确保页面上的TTL在刷新之前永远不会过期-强制在我的系统之一上运行的HTTP客户端获得较慢的负载,而不是不幸的客户端请求。

在我的情况下,这涉及wget一个cron,发送一个特殊的标头以标记请求并req.hash_always_miss基于此进行设置,从而迫使将内容的新副本提取到缓存中。

acl purge {
    "localhost";
}

sub vcl_recv {
    /* other config here */
    if (req.http.X-Varnish-Nuke == "1" && client.ip ~ purge) {
        set req.hash_always_miss = true;
    }
    /* ... */
}

对于您的内容,这可能意味着将Varnish TTL设置为大约5分钟,但是将cron'd wget配置为每分钟发出一次刷新刷新的请求。


我想我明白你的意思。这对于单个页面可能会很好,但是对于其他数千个页面呢?不能在这种规模上使用cron / wget。
标记

本质上,您必须至少声明要在缓存中保持最新的页面。有了此列表,就没有理由在cron脚本中的wget无法帮助您。
Falcon Momot 2013年

我认为这是“外部清漆”的挑战。我最终需要坐下来做出决定,并为每一页实施该决定。没有办法告诉清漆:“ ttl用完了吗?获取新版本,但是直到发生这种情况时才服务旧版本”……?嗯
标记

4

@编辑:

请迅速告诉您,此功能似乎只是在master分支的最新版本中实现的,很可能您的版本可能不支持真正的失效验证 /我已经发布的示例可以使用9999/10000个请求,还有一个糟糕的Bugger仍然必须等待后端完成请求(还是总比没有好;)。


好吧,我不是100%确信为什么前面的评论说它不起作用,而是根据:https : //www.varnish-software.com/static/book/Saving_a_request.html

  • req.grace-定义对象可以过期多长时间以使Varnish仍将其视为宽限模式。
  • beresp.grace-定义beresp.ttl-time Varnish将保留对象多长时间。
  • req.grace-通常在vcl_recv中根据后端的状态进行修改。

我目前正在使用类似手册中所述的配置,并且工作正常……这是我的vcl文件的摘要...

sub vcl_recv {
    # Cache rules above here...
    if (req.backend.healthy) {
        set req.grace = 30d;
    } else {
        set req.grace = 300d;
    }
}

sub vcl_fetch {
    # Fetch rules above here ...

    # If backend returns 500 error then boost the cache grace period...
    if (beresp.status == 500) {
        set beresp.grace = 10h;
        return (restart);
    }

    # How long carnish should keep the objects in cache..
    set beresp.grace = 1h;

    # Actual TTL of cache - If an object is older than this an update will be triggered to the backend server :)
    set beresp.ttl = 1m;
}

请注意,如果您想提供更长的后端响应宽限期(例如在我的配置中出现500错误),则需要设置后端探测...这是我的后端探测的副本。

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = { 
        .url = "/nginx-status";
        .timeout = 500 ms; 
        .interval = 3s; 
        .window = 10;
        .threshold = 4;
    }
}

这对vcl 4.0仍然有效吗?
Gadelkareem '18

0

在Varnish 3中,这是通过“宽限模式”实现的。根据手册[1],您必须添加以下逻辑:

sub vcl_fetch {
  set beresp.grace = 30m;
} // Makes objects to be cached/stored 30 min beyond its max-age/ttl

sub vcl_recv {
  set req.grace = 60s;
} // Allows varnish to serve objects which expired within last minute.

[1] https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode


这将无法实现OP的目标,一个客户端仍将延迟等待从后端提取内容,即使该客户端后面的其他客户端将获得过时的宽限期结果。“一旦TTL过期,要求内容的第一个客户端应停留15秒,而第二个客户端应获得修饰后的副本。” - varnish-software.com/static/book/Saving_a_request.html
大同

抱歉,我没有意识到它如何与第一个过期的请求一起实际使用。
NITEMAN 2013年

也许可以通过一些ttl作弊和内联C来达到期望的目标,从而触发“后台请求”
NITEMAN 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.