让清漆从caching中发送旧数据,而获取新数据?

我正在cachingdynamic生成的页面(PHP-FPM,NGINX),并在他们面前有清漆,这工作得很好。

但是,一旦达到caching超时,我看到这个:

  • 新的客户端请求页面
  • 清漆识别caching超时
  • 客户端等待
  • 清漆从后端获取新的页面
  • 清漆递送新的页面到客户端(并且页面被caching,对于即时得到它的下一个请求)

我想要做的是:

  • 客户端请求页面
  • 清漆识别超时
  • 清漆将旧页面传递给客户端
  • 清漆从后端获取新的页面并将其放入caching

在我的情况下,它不是过时的信息是一个大问题的网站,特别是当我们谈论几分钟内的caching超时。

但是,我不想惩罚用户排队,而是立即提供一些东西。 这在某种程度上可能吗?

为了说明,下面是一个对我的服务器运行攻城战5分钟的示例输出,configuration为caching一分钟:

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发送caching ,听起来很相似,但不是我想要做的。)

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

我目前使用的CMS解决scheme有一个varnish数据库监听器,因此可以通知varnish禁止内容已经改变的页面。 它发送了一个正则expression式的PURGE请求来禁止某些页面。

总结起来,有两种情况我得到了不幸的用户:

  1. 正常清漆TTL的页面到期
  2. 后端用户更改内容,这发送一个清除请求清漆

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

尽pipe如此,对于第二种情况,我创造了一个解决scheme(是的,我意识到这个问题是从第一个案件寻找答案开始的……我的这个问题很差):

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

在目前的体系结构中,我并没有真正的做一个真正的asynchronous请求的奢侈,但是如何在PHP中做一个asynchronous的GET请求? 我能够创build一个GET请求来清除不等待页面加载,但足以触发清漆从后端获取页面并caching它。

最终的效果是数据库监听器发送请求清漆,而当我轮询特定的页面,它从来没有使我的请求“不幸”,但一旦清漆从后端(这可能范围从300ms到2s)突然在那里。

我还没有find一个解决scheme,当正常的TTL用完时,如何避免相同的问题,但我想解决scheme也完全一样,谢恩build议:使用wget触发hash_always_miss ,我只需要足够聪明,得到我要刷新的页面列表。

我用来解决这个问题的解决scheme是确保页面上的TTL永远不会在刷新之前过期 – 强制在我的系统上运行的HTTP客户端获得缓慢的负载而不是不幸的客户端请求。

在我的情况下,这涉及到一个cron上的wget ,发送一个特殊的头来标记请求,并基于此设置req.hash_always_miss ,迫使一个新的内容副本被提取到caching中。

 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分钟左右,但是configuration了一个cron'd wget来configuration每分钟刷新一次caching的请求。

@编辑:

只是一个简单的告诉你,这个function似乎只是刚刚在主分支的最新版本中实现,可能是你的版本可能不支持真正的陈旧,而重新validation尚未/我已发布的示例将服务9999/10000请求一个可怜的臭虫仍然不得不等待请求在后端完成(还是比没有好;)…


那么我不是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中根据后端的状态进行修改。

我目前正在使用像手册说的configuration,它的工作正常…这是我的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; } 

请注意,如果您想要提供较长的后端响应宽限期时间(对于像我的configuration中的500错误),您将需要设置后端探测…这是我的后端探测的副本。

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

在光油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