角待ちは対空

おもむろガウェイン

max-ageはどのようなコンテンツに設定すべきか

可能なコンテンツすべて、だと思っている。

「キャッシュは麻薬」という言葉があるが、大麻OKな国もある的な(多分ぜんぜん違う)。要するに用法用量を守ってちゃんと利用しなきゃいけない。モルヒネも適切に使えば麻酔。

我々はギガが減る時代に生きているのでサーバーに余裕があるからと言ってクライアントにキャッシュをさせないのは間違ってる。サーバーのリソース的にリクエストが捌ききれないのでキャッシュを使うのではなく、ユーザー体験のためにキャッシュを使う時代。

HTTPキャッシュにはExpirationモデルとValidationモデルがあるわけだけど、可能ならば当然前者を使うべき。後者でも「ギガが減る」かという意味では対して変わらないがレスポンスの待ち時間が存在する以上、やはり前者を最初に考えたい。

ではどのようなコンテンツがExpirationモデルで、つまりmax-ageが設定できるだろうか?

まず思い浮かぶのがURLを変えられるコンテンツ。キャッシュはURLをキーにするのでURLが別ならばキャッシュは当然別になる。したがってURLを変更できるのであればいつstaleにすべきかなんて考えず遠い未来までキャッシュ期間を設定してしまって良い。

URLを変えられるコンテンツに該当するのは単純にロゴなどのアセット(ロゴを変えたくなったらファイル名を変えれば良い)などが挙げられるが、意外に見落としがちなのはjsやcssファイルである。jsやcssファイルのパスを変更するのは大変だがクエリパラメータを変更すれば良い。クエリパラメータもURLである。

jsやcssが変更されるのはデプロイ時ほとんどだと思われるのでjsファイルのハッシュ値を計算してクエリパラメータとして付与すればデプロイ時に新しいjsファイルを確実に読み込ませつつ、Expirationモデルのキャッシュをさせることが可能である。

他にはどんなコンテンツにmax-ageを設定させられるか考えると、実は究極的にはURLを変えられるコンテンツしかない。言い換えれば(見方を変えれば)同一のURLでは必ず同一のコンテンツが返ってくるリソースということである。(もちろんmax-ageを少なめに設定してある程度更新が遅れても見えても構わないなどの戦略は取れるが、原則的には、という話でおいとく)

この大原則を踏まえるとどのようにコンテンツを配信すべきかが見えてくる。つまり一度生成したURLでは必ず同一のコンテンツを返し、コンテンツの更新はすべきではない。これは動的なアプリケーションのHTMLやAPIのレスポンスでは不可能だが、例えば画像などでは設計次第では十分可能である。

ちなみに更新というとコンテンツが新しくなることを想像しがちだが削除もありうる。コンテンツが新しくならない設計は十分可能だが、削除されないまでいくと実質不可能だと思われる。しかしながら、すでにオリジンが404だがクライアントにはキャッシュが見えているという状況は、クライアントがキャッシュを参照し別コンテンツを見ている場合に比べて問題になることは少なく感じる。なので削除したコンテンツのキャッシュが残ることは許容してしまえば楽になれる。そう思ってるのはお前だけと言われたら反論はできない。

以上、まとめると

  • max-ageつけられないか最初に考えよう
  • max-ageつけても問題にないURLとコンテンツの関係を設計しよう
    • 404は許容してもいいんじゃないかな

blog.yux3.net

またこのメンバーで集まってリダイレクトしたいね

nginxでURIを書き換えてリダイレクトしたいときrewriteを使うと思う。

典型的には以下のような感じ。

rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gof)$' /data?file=$3.$4. break;

ngx_http_rewrite_modulerewriteディレクティブはURIを書き換えるディレクティブだがリダイレクトも(大体)自動でしてくれる。

第三引数に指定できるフラグはlastbreakredirectpermanentの4種類あるが、なくてもリダイレクトしてくれたりして挙動がよくわからなかったので調べた。


rewrite regex replacement [flag]

rewriteの構文はこんな感じ。渡ってきたURIをregexに従ってreplacementに置き換える。

その際、replacementがhttp://またはhttps://または$schemeで始まる際、フラグに関係なく処理は中断され、redirectフラグが指定された場合と同じ挙動する。

redirectフラグは302リダイレクトを返すフラグなので、結果的にreplacementがhttp://などのスキーマから始まっていた場合302リダイレクトが返ることになる。その際続く処理は中断されるのでわざわざbreakを付ける必要はない。

つまりredirectフラグがなくてもリダイレクトしてくれるのはなぜかというとスキーマ始まりのURLを書いているからであった。

ridirectフラグの説明には

used if a replacement string does not start with “http://”, “https://”, or “$scheme”;

とreplacementがスキーマで始まらない場合に使われると書いてある。

つまり、replacementにスキーマがついているかを最初に考え、次にフラグによってどういう挙動をするかを考えればrewriteの挙動が見えてくる。

lastbreakの挙動は巷に良い解説記事が溢れているので言及しない。permanentは301でリダイレクトが返るフラグである。

blog.yux3.net

sedとperlと部屋とワイシャツと私

MacOSのsed-iオプションのあとに空文字を指定しても(-i'')in-place(上書き)にしつつバックアップファイルは作らないみたいな動作はできない。

sed -i'' -e 's/foo/bar/' test.txt

するとtest.text-eというファイルができて辛い。ちなみに''がなくてもだめ

対してperl

perl -i -pe 's/foo/bar/' test.txt

で期待した挙動になる。

やっぱperlやな!とおもったら

sed -i '' -e 's/foo/bar/' test.txt

のようにスペースを空けると上書きしつつバックアップは取らないとう挙動になる。

-i extension Edit files in-place, saving backups with the specified extension. If a zero-length extension is given, no backup will be saved. It is not recommended to give a zero-length extension when in-place editing files, as you risk corruption or partial content in situations where disk space is exhausted, etc.

特にマニュアルにはスペース開けろって書いてない気がする。-i'.backup' がいけるのでいけると思ってた。

なにはともあれsedには後で謝っておこうと思いました。

blog.yux3.net

年内には埋めたいという気持ちでやってます。