使用 Nginx 和 Etags 对动态内容进行服务器端缓存

Server side caching of dynamic content with Nginx and Etags

我有一个 CouchDB 数据库,前面有一个 Nginx 反向代理。 CouchDB 的一些响应需要很长时间才能生成(是的,这是一个糟糕的选择,但现在需要坚持下去),我想用 Nginx 缓存它们。 (目前 Nginx 只支持 SSL。)

CouchDB 支持 Etag,因此理想情况下,我希望 Nginx 也为愚蠢的客户端缓存 Etag。客户端不使用 Etags,他们只会查询 Nginx,Nginx 将其缓存的 Etag 转到 CouchDB,然后将缓存的响应或新响应发送回客户端。

根据文档我的理解是Nginx目前无法做到这一点。我错过了什么吗?是否有支持此设置的替代方案?或者唯一的解决办法是手动使Nginx缓存失效?

我假设您已经看过 varnish 并且没有发现它适合您的情况。有两种方法可以达到你想要的效果。

用nginx

Nginx 有一个默认值 caching mechanism that you can configure 供您使用。

如果还是不行,你应该给用第3方编译的Nginx Ngx_Lua module a try. This is also conveniently packaged along with other useful modules and the required Lua environment as Openresty.

使用 Ngx_Lua,您可以使用 shared dictionary 来缓存您的 couchdb 响应。顾名思义,共享字典在 Ngx_Lua 的执行环境中使用共享内存区域。这类似于 proxy_cache 在 Nginx 中的工作方式(它还在 Nginx 的执行环境中定义了一个共享内存区域),但具有可以对其进行编程的额外优势。

构建 couchdb 缓存所需的步骤非常简单(使用这种方法,您无需向客户端发送 etag)

  1. 您向 couchdb 发出请求
  2. 您保存了 {Url-Etag:response}
  3. 下次请求使用 HEAD 请求进行相同的 url etag 查询。
  4. 如果响应 etag 与 {Url-Etag:response} 对匹配,则发送缓存的响应,否则使用 (get/post) 方法再次查询 couchdb 并在将响应发送到客户端之前更新 {Url-Etag:response} 对.

当然,如果您手动编写缓存程序,则必须定义最大缓存大小和从缓存中删除旧项目的机制。 lua_shared_dict 指令可以帮助您定义缓存响应的内存大小。在共享字典中保存值时,您可以指定值将保留在内存区域的时间,之后它将自动过期。结合共享字典的最大缓存大小参数和缓存时间参数,您应该能够为您的用户编写相当复杂的缓存机制。

用erlang

因为 couchdb 是用 erlang 编写的,所以您的机器上已经有一个 erlang 环境。因此,如果您可以在其中编程,您可以使用 mnesia 创建一个非常强大的分布式缓存。步骤是一样的。 Erlang 计时器可以与 gen_* 行为相结合,使您的项目自动到期,而 mnesia 具有监视其内存使用情况并通知您的功能。这两种方法几乎是等价的,唯一的区别是 mnesia 可以分发。

更新

正如@abyz 所建议的那样,redis 在缓存方面也是不错的选择。