Varnish 默认宽限行为

fla*_*lar 4 caching varnish http-caching varnish-vcl

有一些负载较重的 api 资源,其中响应是动态的,为了减轻源服务器的负载,我们使用 Varnish 作为前面的缓存层。API 使用范围从 max-age=5 到 max-age=15 的缓存控制标头进行响应。由于我们使用低缓存 ttl,因此许多请求仍然会在后端获取中结束。从这个意义上说,我们不确定我们是否正确理解清漆请求在恩典方面的合并。我们没有触及任何宽限设置,使用 VCL 的宽限和从后端发送 stale-while-revalidate 标头。

\n

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

\n

Thi*_*ryn 12

Varnish 中对象生命周期的基础知识

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

TTL + grace + keep
Run Code Online (Sandbox Code Playgroud)

让我们来分解一下:

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

这是执行顺序:

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

默认值

请求合并怎么样?

Varnish 中用于请求合并的等待列表仅用于非缓存对象或超过宽限时间的过期对象。

以下场景不会触发请求合并:

TTL > 0
TTL + grace > 0
Run Code Online (Sandbox Code Playgroud)

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

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

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

绕过等候名单

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

请求合并仅适用于可缓存内容。合并响应永远无法满足的有状态内容应绕过等待列表。如果没有,将进行序列化。

序列化是一件坏事。这意味着排队的请求无法被响应满足,并且会被串行处理。这种队头阻塞可能会导致严重的延误。

这就是为什么无状态/不可缓存的内容应该绕过等待列表。

绕过等待列表的决定是由命中未命中缓存做出的。这个机制缓存了不缓存的决定。

为此使用以下代码:

set beresp.ttl = 120s;
set beresp.uncacheable = true;
Run Code Online (Sandbox Code Playgroud)

您可以在 Varnish 的内置 VCL 中找到这种 VCL 代码。Set-Cookie当找到标头或发生标头时会触发它Cache-Control: private, no-cache, no-store

这意味着在接下来的 2 分钟内将从源提供对象,并且将绕过等待列表。当下一次缓存未命中将返回可缓存响应时,该对象仍存储在缓存中,并且命中未命中不再适用。

考虑到这一点,不要设置beresp.ttl为零至关重要。因为这会使命中/未命中信息过期,并且仍然会导致下一个请求最终出现在等待列表中,即使我们知道响应将不可缓存。