缓存失效
“计算机科学领域只有两件难事:缓存失效和命名东西”——Phil Karlton
一旦一个URL被以gateway cache方式缓存,缓存将不再针对内容而请求程序。这能令缓存提供最快的响应,并减少程序负载。但是,你面临着传送过期内容的危险。走出此困境的一种办法是使用超长缓存周期,但是当内容被更新时并不能有效通知到gateway cache。反向代理通常提供一个频道来接收这种通知,一般通过特殊的Http请求实现。
虽然缓存无效化是非常强大的,但还是要尽量避免它。如果你在令某些内容“无效化”时失败了,过期缓存有可能被继续提供很长一段时间。取而代之的是,使用短的缓存周期,或者使用validation模型,并调整你的控制器,令其高效地进行验证检查,如同前面通过Validation来优化代码所解释的那样。
再有,因为“失效化”对于每一种反向代理来说都是独立的话题,使用这个概念会把你拴到特定的反向代理上,或者需要额外的努力以支持这些不同的代理。
但是有时,你需要这种通过显式进行“无效化”所获得的额外性能。为了能够invalidation,你的程序需要侦测内容是何时被改变的,然后通知缓存移除包含了“从缓存中获取到该内容数据”的URLs。
如果你需要使用cache invalidation,看一下FOSHttpCacheBundle。这个bundle提供的服务通过多种cache invalidation概念来提供帮助,还对常用的缓存代理做了配置上的文档说明。
如果是一个内容对应一个URL的话,PURGE
模型最为适合。你用PURGE
HTTP方法发送请求给缓存代理(使用“PURGE”这个词是命名约定,技术角度讲它可是任何字符串)来替代GET
,并且让缓存代理侦测到它,然后从缓存中移除数据,从而不必回到程序去获取一个响应。
下面代码演示了如何配置Symfony反向代理,以支持PURGE
HTTP方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// app/AppCache.PHP
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
use Symfony\Component\Httpfoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// ...
class AppCache extends HttpCache
{
protected function invalidate(Request $request, $catch = false)
{
if ('PURGE' !== $request->getMethod()) {
return parent::invalidate($request, $catch);
}
if ('127.0.0.1' !== $request->getClientIp()) {
return new Response(
'Invalid HTTP method',
Response::HTTP_BAD_REQUEST
);
}
$response = new Response();
if ($this->getStore()->purge($request->getUri())) {
$response->setStatusCode(200, 'Purged');
} else {
$response->setStatusCode(404, 'Not found');
}
return $response;
}
} |
你必须以某种方式来保护PURGE
HTTP方法以避免随机用户清除你的缓存数据。
Purge指令让缓存删除一个资源,包括这资源的所有变种(根据Vary
头来操作,参考前文)。另一个清除缓存的可选办法是,refreshing(刷新)一个内容。刷新的意思是,缓存代理被指示放弃其本地缓存并再次取出内容。这样做之后,新内容已经可以在缓存中使用。刷新的缺点是,并未对内容变体实施无效化。
在很多程序中,相同的内容位(content bit)被用于不同URL的多个页面中。这种情况下,还有更灵活的办法:
Banning 通过对URL匹配正则表达式,或其他标准,来使响应无效。
Cache tagging 允许你对每个用在响应中的内容添加一个标签,以便你能够令所有包含了特定内容的URL无效。