清漆默认宽限期行为

Varnish default grace behavior

有一些 api 负载很重的资源,其中响应是动态的,为了卸载我们使用 Varnish 作为前端缓存层的原始服务器。 api 以 cache-control headers 响应,范围从 max-age=5 到 max-age=15。由于我们使用的是低缓存 ttl,因此很多请求仍然以后端获取结束。从这个意义上说,我们不确定我们是否理解清漆请求在优雅方面是否正确合并。我们没有触及任何宽限度设置,使用来自 VCL 的宽限期 og 从后端发送 stale-while-revalidate headers。

所以问题是;资源从缓存中过期后,所有对该资源的请求都将在 varnish 中等待,直到资源再次在缓存中刷新,以防止雷群问题?或者默认的宽限期设置是否会阻止“等待”请求,因为在后端获取完成时将向它们提供“陈旧”内容?从文档中我们不清楚默认值是如何工作的。

关于 Varnishobject 生命周期的基础知识

object 的总生命周期是以下各项的总和:

TTL + grace + keep

让我们分解一下:

  • TTL 定义内容的新鲜度
  • Grace 用于异步重新验证过期内容
  • Keep 用于过期内容的同步重新生效

执行顺序如下:

  • 只要 TTL 未过期,就会从缓存中提供 object
  • 当 TTL 等于或小于零时,需要重新验证
  • 只要剩余 TTL(可能小于零)和宽限时间之和大于零,就可以提供陈旧的内容
  • 如果有足够的宽限时间,Varnish 将在提供陈旧内容的同时异步重新验证内容
  • 如果 TTL 和宽限期都已过期,则需要同步重新生效
  • 同步重新验证使用等待列表并受请求合并影响
  • 剩余的保持时间将确保 object 保持不变,以便可以发生条件请求

默认值

请求合并怎么样?

Varnish中用于请求合并的等待列表仅用于non-cached objects或过期的objects已经过了宽限期。

以下情况不会触发请求合并:

TTL > 0
TTL + grace > 0

当 object 新鲜或在宽限期内时,无需使用等待列表,因为内容仍将从缓存中提供。在 objects 宽限期的情况下,单个异步后端请求将被发送到源以进行重新验证。

当 object 不在缓存中或超出宽限期时,需要同步重新验证,这是一个阻塞操作。为避免在多个客户端请求相同 object 时出现问题,使用等待列表并将这些请求合并为一个后端请求。

最后,所有排队的请求都由同一个后端响应并行满足。

绕过等候名单

但这里有一条关于请求合并的重要评论:

Request coalescing only works for cacheable content. Stateful content that can never be satisfied by a coalesced response should bypass the waiting list. If not, serialization will take place.

序列化是一件坏事。这意味着排队的请求不能被响应满足,并且被串行处理。此 head-of-line 阻塞会导致严重延迟。

这就是 stateless/uncacheable 内容应该绕过等候名单的原因。

绕过等待列表的决定是由 hit-for-miss 缓存 做出的。这种机制缓存决定不缓存。

以下代码用于此:

set beresp.ttl = 120s;
set beresp.uncacheable = true;

这是您可以在 Varnish 的 built-in VCL 中找到的那种 VCL 代码。当找到 Set-Cookie header 或出现 Cache-Control: private, no-cache, no-store 时触发。

这意味着在接下来的 2 分钟内,object 将从源站提供服务,等待名单将被绕过。当下一个缓存未命中将 return 可缓​​存响应时,object 仍存储在缓存中,并且 hit-for-miss 不再适用。

考虑到这一点,不要将 beresp.ttl 设置为零是至关重要的。因为那会使 hit-for-miss 信息过期,并且仍然会导致下一个请求在等待列表中结束,即使我们知道响应将不可缓存。