Skip to content
所有文章 ‹ Part 15 of 18 · Cache 不是方塊,是一條鏈
工程 · 2 min read

Stale-while-revalidate:先回舊檔,背景再刷新

Stale-while-revalidate 先回舊副本,再在背景 refresh。只要 refresh 一直失敗,副本就永遠新鮮不起來,還帶著很大的 Age 往前傳。

副本過期時,LB cache 先把舊副本回出去,再在背景 refresh。Refresh 一直失敗,副本就永遠新鮮不起來。

Proxy 路線的 LB cache 不讀 bypass header(Bypass header 只在有規則的地方有效)。但它的副本早就過期了,為什麼還一直回給 Akamai?

request LB cache,副本已過期 立刻回傳舊副本 背景 refresh 成功:副本恢復新鮮 失敗:副本維持過期,下一個 request 再試
LB cache 先立刻回傳舊副本,只有背景 refresh 成功,副本才會恢復新鮮。
  • 這個行為在 HTTP 標準裡叫 stale-while-revalidate(RFC 5861)。我們的 LB cache 用自己的設定開啟它。
  • 這個設定是過期後還能回舊副本的秒數。我們 proxy 後端的值是 86400 秒(1 天)。
  • 沒有人刻意選這個值,它是預設值(三個地方都在設定 TTL)。
  • 好處:回應很快。origin 掛掉時,使用者還是拿得到檔案。
  • 代價:如果背景 refresh 每次都失敗,副本就一直是過期的。

舊副本帶著很大的 Age 往前傳

  • LB cache 把舊副本交給 Akamai 時,Age 已經超過 3600。
  • Akamai 算出的剩餘新鮮時間是 0 或負數。
  • 所以 Akamai 只能保留它 1 秒(max-age=1),下一個 request 又要去問。
  • 這就是 Cache 的新鮮度:fresh、stale 和 304 說的:前面的 cache 只會跟它收到的副本一樣新。

這個後端在 IaC 裡沒有任何 cache 設定。但 cache 開著,所以有一整套預設值。讓 bug 發生的 86400,就藏在沒人寫下來的預設值裡。

「先回舊檔」是一種保護。前提是背景的 refresh 真的會成功。

參考來源:RFC 5861: HTTP Cache-Control Extensions for Stale Content

延伸閱讀:Cache 的新鮮度:fresh、stale 和 304、三個地方都在設定 TTL、Bypass header 只在有規則的地方有效、Proxy 不接受 HEAD,刷新永遠失敗。或回到系列總覽。

↑↓ 移動 ↵ 開啟 esc 關閉