有异步更新的 HTTP 缓存代理吗?

is there HTTP caching proxy with async updates?

我不得不在一个很慢的API前面放一个缓存服务。 api 响应大约需要 40 秒,这对我的用户来说太长了。我想使用 Varnish 之类的东西来缓存响应。

这是我的问题:

当缓存服务第一次被命中时,大约需要 40 秒才能从上游获得响应 API。所有连续的请求都将直接从缓存中获得服务。当缓存 TTL 过期时,缓存服务必须再次命中慢 API 并等待 40 秒,这是不可接受的。有没有办法通过进行某种异步后台缓存更新来避免它?如果可以,Varnish 能做到吗?

为简单起见,我们假设所有客户端请求都相同。

如果缓存服务每秒被命中数百次,情况实际上会更糟。 40 秒长的等待刷新缓存将使数千个客户端请求排队,这可能会导致不同类型的问题,包括断开连接。我假设 Varnish 足够聪明,它只会触发一次上游 API 调用并将其他请求排队,直到它得到响应。

Varnish 或任何替代方案是否保留最后一次正确的副本?如果我的慢速 API 出现故障并且根本没有响应怎么办,是否可以在缓存过期后从缓存中为 LKGC 提供服务?

实现这一切的最佳软件是什么?

Varnish 通过宽限模式绝对支持这一点。您将需要一些 VCL code magic to enable grace mode。这是它的内容:

  • 初始请求会很慢。它将使用一些 TTL 进行缓存。
  • 当为初始请求定义宽限期时,Varnish 将缓存的对象保留在其 TTL 之后。那个时间叫做"grace period".
  • 如果后续请求是针对已过期但仍在其宽限期内的对象,Varnish 将return一个陈旧的缓存对象,在执行异步后端请求时 .

因此,只有初始请求会很慢。客户将立即收到刷新的请求。

基本上,您希望将 "healthy backend grace period" 设置为后端生成响应所需的最长时间。示例:

sub vcl_hit {
    if (obj.ttl >= 0s) {
        # normal hit
        return (deliver);
    }
    # We have no fresh fish. Lets look at the stale ones.
    if (std.healthy(req.backend_hint)) {
        # Backend is healthy. Limit age to 45s.
        if (obj.ttl + 45s > 0s) {
            set req.http.grace = "normal(limited)";
            return (deliver);
        } else {
            # No candidate for grace. Fetch a fresh object.
            return(fetch);
        }
    } else {
        # backend is sick - use full grace
        if (obj.ttl + obj.grace > 0s) {
            set req.http.grace = "full";
            return (deliver);
        } else {
            # no graced object.
            return (fetch);
        }
    }
}

在本例中,我将其设置为 45 秒。这确保涵盖慢速 API 请求可能需要的 40 秒。