テレビのアニメはどこから来る? / 第15話

第15話:イトは、古いポスターを消さずに『まだ同じ?』と聞いた|キャッシュはいつ更新する?

ピコルート第15話。originだけ新版なのに、browserとedgeには古いposterが残った。確認previewまで8秒、イトは全cacheを消すか、validatorで『まだ同じ?』と聞くかを選びます。

キャッシュブラウザキャッシュCDNキャッシュ反映待ち10分更新

イトの指が、赤い全消去leverに触れた。

あと一センチ下ろせば、古いposterは消える。

新しいposterも、関係のないCSSも、ほかの利用者が使えるcopyも、一度に冷たい空棚へ戻る。

確認previewまで、あと八秒。

第14話で二人目を速くしたedge shelfには、昨日のposterが残っている。

browserの手元にも、同じ昨日版がある。

遠いoriginだけは、上映時刻を直した新版へ変わっていた。

イト

古いなら、全部消せば確実だよね

ピコ

消す前に、その古いcopyが持っている札を見ない?

ユイ

旧版かどうかを、originへ尋ねるための札ですね

ピコがposter cardを裏返した。

小さなfingerprintのような印が光っている。

ETag: "poster-v1"

残り七秒。

古いcopyは、二つの場所にある

イトの前に、二つの保管場所が開いた。

一つは、一台のbrowserだけが使う引き出し。

もう一つは、複数のviewer requestへ応答するedgeの棚。

RFC 9111 HTTP Cachingは、一人の利用者専用のcacheをprivate cache、複数の利用者へ再利用するcacheをshared cacheとして分けている。

browser cacheはprivate cacheとして働くことがある。

CDN edge cacheはshared cacheとして働くことがある。

同じposterが両方にあっても、引き出しは一つではない。

browserだけ消しても、edgeが旧版を返すかもしれない。

edgeだけ更新しても、browserが手元の旧版を使える状態なら、画面は変わらないかもしれない。

マコト

古いposterが一枚あるのではなく、経路の途中に別々のstored responseがあるんだね

イト

だから『cacheを消した』だけでは、どこを変えたか分からないのか

二つの旧posterには、どちらも同じETagが残っていた。

ETagは、そのrepresentationを見分けるvalidatorとして使える。

fingerprintそのものが内容を運ぶのではない。

手元のcopyとoriginのcurrent representationが同じかを比較する手がかりだ。

freshなら再利用、staleなら再確認

cache shelfの時計が、白から橙へ変わった。

freshness lifetimeが終わった。

stored responseがfreshな間は、originへvalidationせず再利用できる場合がある。

それが、cache hitを速くする。

しかしfreshでなくなったresponseはstaleだ。

このfictional configurationでは、stale posterをそのまま返す許可はない。

そのまま返す前に、現在も使えるかを確かめなければならない。

RFC 9111では、cacheがstored responseをそのまま使えないとき、conditional requestでnext inbound serverへvalidationを求め、同じresponseをfreshenするか、新しいresponseへ置き換えられる。

イトは赤いleverを見た。

全部消せば、old copyを誤って返す心配は減る。

でも、消したcacheは次のrequestで取り直しになる。

直す必要のない材料までcold missへ戻せば、originへのrequestと待ち時間が一度に増える。

残り五秒。

三つの手

ピコが、全消去leverの前へ三枚のcardを置いた。

  1. staleな旧posterを、そのまま返す
  2. browserと全edgeのcacheを、一括で空にする
  3. 旧posterを残し、validatorでoriginへ再確認する

一枚目は最速だ。

けれど、このconfigurationではstale responseを使う条件を満たさない。上映時刻が違うposterをもう一度見せる。

二枚目なら、旧posterは消える。

同時に、問題のないcacheまで失う。確認previewの直前に、大きなcold missを自分で作る。

三枚目はorigin往復が必要だ。

その代わり、古いbodyを捨てずに「いまも同じか」だけを先に聞ける。

同じならbodyをもう一度運ばずに使える。

違うなら、そのときだけ新版を受け取る。

ピコ

速さを守るために、何を残す?

ユイ

新しさを守るために、何を聞きますか?

イトは、赤い全消去leverから指を離した。

旧poster cardは、捨てない。

裏面のETagだけを、小さなconditional request envelopeへ入れた。

GET /media/finale-poster
If-None-Match: "poster-v1"

残り四秒。

browserからedge、edgeからoriginへ

conditional requestは、まずbrowserのprivate cacheからedgeへ進んだ。

edgeにも、同じ旧posterとETagがある。

しかしedgeのcopyもstaleだ。

edgeは自分だけで「currentと同じ」とは決められない。

requestをoriginへ進める。

イトは、二つの旧posterがresponse laneへ飛び出さないようgateを押さえた。

「比べ終わるまで、返さない」

RFC 9111のvalidation手順では、ETagを持つstored responseをvalidateするとき、cacheはentity tagをIf-None-Matchへ載せられる。受け取った側は、そのtagとcurrent representationを比較する。

originの比較台に、二枚のfingerprintが並んだ。

requestが持ってきた旧版。

originが持つ新版。

同じではない。

残り三秒。

同じなら304、違えばfull response

もしoriginのcurrent ETagもposter-v1なら、bodyを再送する必要はない。

その場合、conditional GETへ304 Not Modifiedを返し、stored bodyを再利用できる。

RFC 9110の304 Not Modifiedは、clientがvalidなrepresentationをすでに持つため、target representationを転送する必要がないことを示すresponseだ。

今回は違う。

originのcurrent ETagは、新版の札だった。

If-None-Matchの旧tagとは一致しない。

originはconditional GETを通常どおり処理し、新しいbodyを含むfull responseを返した。

HTTP/1.1 200 OK
ETag: "poster-v2"

青い新版posterが、originからedgeへ届く。

edge shelfの旧cardだけが裏返る。

responseはbrowserへ進む。

browser drawerの旧cardも、新版へ置き換わる。

イトが赤い全消去leverから手を離し、古いposterのfingerprint tokenだけをconditional request envelopeへ入れ、originから届いた青い新版responseでedgeとbrowserの旧cardだけを裏返している
古いbodyを捨てずにvalidatorだけを送り、違うと分かったときだけ新版へ置き換える。

消さずに、必要な場所だけ変えた

残り一秒。

確認端末のposterが、修正後の上映時刻へ変わった。

edgeとbrowserの旧posterは新版になった。

同じ棚にあったCSSも、別のimageも残っている。

全消去はしていない。

今回のrevalidationは、変更があったためoriginまで一往復し、poster bodyも運び直した。

即時のcache hitよりは待った。

それでも、関係のないstored responseを全部捨てるcostは避けられた。

もし変更がなければ、304でstored bodyを使い続けられた。

validatorが付いていないresponseなら、同じ方法で効率よく確認できるとは限らない。

cacheは「消すか、信じるか」の二択ではない。

残して、確かめて、同じなら使う。

違うなら、そのresponseだけを入れ替える。

マコト

消す範囲ではなく、確認する相手とcopyを選んだんだね

イト

古いものを見つけたら、まず『まだ同じ?』と聞ける

preview開始の光が点いた。

イトが捨てたのは、古いposterではない。

「まだ同じだ」という思い込みを、validatorでoriginへ確かめた。

posterの次に、細い箱が並んだ

修正版posterの下で、再生buttonが光った。

イトが押す。

巨大なvideo fileが一箱で届くと思った。

しかし受付に現れたのは、細い箱の列だった。

GET /video/finale/segment-001
GET /video/finale/segment-002
GET /video/finale/segment-003

一箱目が届くと、画面はもう動き始めた。

二箱目は、再生中に向かってくる。

三箱目は、まだ遠い。

posterの更新は終わった。

今度は、全部届く前に始まるvideoの道が動き出した。

次回:動画は、全部そろう前になぜ始まる?

browserとedgeの旧posterを、validator付きconditional requestでoriginへ確かめた。

同じなら304、違った今回はfull 200で新版へ置き換わった。

次に流れ込むのは、連続する小さなvideo segmentだ。

次回、ピコルート第16話。

最初の箱だけで、再生を始める。

画面のむこう側をもっと知る

browser cache、CDN cache、freshness、revalidationの違いを図で整理するなら、キャッシュとはで確かめられます。

この物語を、解説で深める

第15話で生まれた疑問を、解説記事で少し深く見ていきます。物語で感じた不思議さを残したまま、言葉と仕組みを順番に整理しましょう。

キャッシュとは?表示が速くなる仕組みと、古い情報が残る理由を読む