缓存动态内容的反向代理

Caching reverse proxy for dynamic content

我本来想在 Software Recommendations 上询问,但后来我发现这可能是一个太奇怪的要求,需要先澄清一下。

我的观点是:

基本上,代理应该包含一个将 etag 映射到响应内容的缓存。 etag 从服务器获取,在最常见的情况下,服务器根本不处理响应内容。

应该是这样的:代理总是向服务器发送一个请求然后

为简单起见,我省略了 if-none-match header 的处理,这很明显。

我这样做的原因是最常见的情况 1.1 可以在服务器中非常有效地实现(使用其缓存映射请求到 etags;内容不缓存在服务器中),因此大多数请求都可以在服务器不处理响应内容的情况下处理。这应该比首先从侧缓存中获取内容然后提供它更好。

在案例1.2中,有两次请求到服务器,这听起来很糟糕,但并不比服务器请求侧缓存并未命中更糟糕。

Q1:我想知道,如何将第一个请求映射到 HTTP。在情况 1 中,它就像一个 HEAD 请求。在情况 2 中,它就像 GET。两者之间的决定取决于服务器:如果它可以在不计算内容的情况下提供 etag,则为情况 1,否则为情况 2。

Q2:有反向代理做这样的事情吗?我读过有关 nginx、HAProxy 和 Varnish 的文章,但似乎并非如此。这让我想到 Q3: 这是个坏主意吗?为什么?

Q4:如果不是,那么哪个现有代理最容易适应?

一个例子

来自用户 U1 的类似 /catalog/123/item/456 的 GET 请求提供了一些内容 C1etag: 777777。代理存储 C1 在密钥 777777 下。

现在同样的请求来自用户 U2。代理转发它,服务器 returns 只是 etag: 777777 并且代理很幸运,在其缓存中找到 C1(案例 1.1)并发送它到 U2在这个例子中,客户端和代理都不知道预期的结果。

有趣的是服务器如何在不计算答案的情况下知道 etag。例如,它可以有一条规则,说明这种形式的请求 return 对所有用户的结果相同,假设允许给定用户看到它。因此,当来自 U1 的请求到来时,它会计算 C1 并将 etag 存储在键 /catalog/123/item/456 下。当相同的请求来自 U2 时,它只是验证了 U2 被允许查看结果。

Q1: 是GET请求。服务器可以在没有 body.

的情况下回答“304 未修改”

Q2: openresty(nginx加上一些额外的模块)可以做到,但是你需要自己实现一些逻辑(见下面更详细的描述)。

Q3:根据您问题中的信息,这听起来像是一个合理的想法。只是一些思考的食物:

  • 您也可以将页面拆分为 user-specific 和可以独立缓存的通用部分。

  • 您不应该期望缓存永远保留计算的响应。因此,如果服务器 returns a 304 not modified with etag: 777777 (根据您的示例),但缓存不知道它,您应该可以选择强制 re-building 答案,例如另一个带有自定义 header X-Force-Recalculate: true.

  • 的请求
  • 不完全是你问题的一部分,但是:确保设置正确的 Vary header 以防止缓存问题。

  • 如果这只是关于权限,您也许还可以使用签名 cookie 中的权限信息。缓存可以在不询问服务器的情况下从cookie中获取权限,并且cookie由于签名是防篡改的。

Q4:我会为此使用 openresty,特别是 lua-resty-redis module。将缓存的内容放入 redis key-value-store 中,并以 etag 为键。您需要在 Lua 中编写查找逻辑代码,但不应超过几行。