1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CDNでのキャッシュ時間を延ばすことによる効果

Last updated at Posted at 2024-10-15

初めに

CDNでサイト内の動的コンテンツを結構長めにキャッシュすることになりました。
キャッシュ効率を上げるのに「キャッシュする時間が長けりゃそれでいいというわけではない」というのは感覚的には分かっていたのですが、
説明せよと言われたら何とも言えない感じだったので、自分なりの回答を得るべく何とか計算してみようとしました。

前提知識

  • CDNは何のための物なのか
  • CDNに関連する用語(キャッシュ、オリジン等)

この記事で確かめること

キャッシュ時間延ばせば、オリジンリクエストはどれだけ抑えられるのか?
なるべく簡単な例を簡単な算数で考えてみましょう!

結論を急ぐ!

前準備

今回考えるのはキャッシュ効率です。それを出すにはCDNでキャッシュが効いてくれなかった時に発生するオリジンリクエストの数を計算する必要があります。

キャッシュが効かなくなる場合はどういう時かを考え、それに合った式を立てていくことになります。

キャッシュが切れた直後のオリジンリクエスト

  • キャッシュがある時はキャッシュが返り続ける
  • キャッシュが切れた直後は瞬間的にオリジンリクエストが発生する

という動きになると考えます。
特にこのキャッシュが切れた直後のオリジンリクエスト数は、

  • その時間帯の1秒あたりのリクエスト数($D_{\rm Req}$)
  • CDNからのオリジンリクエストの処理(CDNへ返ってくるまでの)時間($T_{\rm Proc}$秒)
    ※以下、長いので「オリジンリクエストの処理時間」とだけ言うこととする

で決まり、$\lfloor D_{\rm Req} \times T_{\rm Proc}\rfloor + 1$で出せます。
この「$+1$」はキャッシュが切れた直後の最初のリクエスト分であり、そのリクエストが処理されて返るまでオリジンリクエストが$\lfloor D_{\rm Req} \times T_{\rm Proc}\rfloor$回発生するということです。

例えば、1分あたり100万リクエスト(1秒あたり16666)で、1リクエストあたりの処理時間が0.5秒だとしたら、

$$
\lfloor D_{\rm Req} \times T_{\rm Proc}\rfloor + 1 = 16666 \times 0.5 + 1 = 8,334回
$$

例えば、1分あたり10リクエスト程度で、1リクエストあたりの処理時間が0.5秒だとしたら、そのリクエスト処理中に次のリクエストが来ることは無いので1回になります。1

$$
\lfloor D_{\rm Req} \times T_{\rm Proc}\rfloor + 1 = 0 + 1 = 1回
$$

キャッシュ時間のパターン

  1. キャッシュ時間短め
    • キャッシュ時間が1分~1時間
    • 範囲は1時間を考える
    • その範囲におけるリクエストの分布は一様と見做せる
  2. キャッシュ時間中くらい
    • キャッシュ時間が1時間~1日
    • 範囲は1日を考える
    • その範囲のリクエストの分布は一定の動きがある (例えば、昼は凹んで夜は膨らむ等)
  3. キャッシュ時間長め
    • キャッシュ時間が1日~1年(動的コンテンツをここまでキャッシュするのはリスクが高いですが・・)
    • 範囲は1カ月とか1年を考える
    • その範囲のリクエストの分布は、季節によって一定の動きがあるかもしれないし、ランダムかもしれない

長めのキャッシュ時間を考えようとするとそれだけ計算しづらい分布になります。
また、(ネタバレにはなってしまいますが)キャッシュ時間短めでも、もし十分効果があるならばそれ以上長くしても目立った差はないので、ここではキャッシュ時間短めのパターンだけ考えます。

仮定

  • 1つのURL(というかキャッシュキー)に対するリクエストだけ考える
  • $s$分( $0<s≤60$ )に$N$( $≥1$ )回リクエストが来る場合を考える
  • 1時間あたりのリクエストを考える
    すなわち、全リクエスト数は$\lfloor 60 \times \frac{N}{s} \rfloor$回であり、オリジンリクエスト数はこれを超えることは無い
  • リクエストの分布は1時間の間に一定の間隔でバラついているとする
  • オリジンリクエストの処理時間は常に一定($T_{\rm Proc}$秒)とする
  • 例えばキャッシュ時間を25分とかにした場合、1時間のうち2回しかキャッシュが切れないパターンと、3回切れるパターンがある。計算する場合は1少ない方に寄せることとする
    ※後述の式の、$\lfloor \frac{60}{t} \rfloor$ の意味がこれです

計算してみる

オリジンリクエスト数の計算式

キャッシュ時間$t$分( $0<t≤60$ )とした時の1時間あたりのオリジンリクエスト数$R_{\rm Orig}$は

$\frac{N}{s} \times t \geq 1$の時2

\begin{align*}
R_{\rm Orig} &= (
  \lfloor
    D_{\rm Req} \times T_{\rm Proc}
  \rfloor + 1
) \times
\lfloor
  \frac{60}{t}
\rfloor \\
&=
\left(
  \lfloor
    \frac{N}{s\times60} \times T_{\rm Proc}
  \rfloor + 1
\right) \times
\lfloor
  \frac{60}{t}
\rfloor
\end{align*}

と書けます。

この式から分かること

  • キャッシュ時間が短いほどオリジンリクエスト数は増える
    ※1時間のうち、キャッシュが切れる回数は$\lfloor \frac{60}{t} \rfloor$であることから分かる
  • キャッシュが切れた直後のオリジンリクエスト数$\lfloor \frac{N}{s\times60} \times T_{\rm Proc} \rfloor$が0に近い程キャッシュが効く
    ※0になると$R_{\rm Orig} = \lfloor \frac{60}{t} \rfloor$回で、キャッシュが切れる度に1回だけオリジンリクエストが発生するということになる
  • キャッシュする時間が処理時間以下($t \leq T_{\rm Proc}$)、あるいはそれに近いとキャッシュする意味が無い
    ※普通そんな短くはしないけれど

色々な数値を入れて様子を見てみる

※ここでのリクエスト数はあくまで、1キャッシュキーに対するリクエスト数ですので、実際のリクエスト数に当てはめる場合はそれを良く踏まえてください。


1分に47500回リクエスト、$T_{\rm Proc}$=0.5秒とすると

キャッシュ時間 1時間あたりのオリジンリクエスト キャッシュヒット率
なし 2,850,000回 0.000%
1分 23,760回 99.166%
2分 11,880回 99.583%
3分 7,920回 99.722%
5分 4,752回 99.833%
10分 2,376回 99.917%
20分 1,188回 99.958%
60分 396回 99.986%

リクエストの処理時間が遅くても、リクエストが集中してると1分キャッシュでも中々良いキャッシュヒット率ですね。


1分に5000回リクエスト、$T_{\rm Proc}$=0.6秒とすると

キャッシュ時間 1時間あたりのオリジンリクエスト キャッシュヒット率
なし 300,000回 0.000%
1分 3,060回 98.980%
2分 1.530回 99.490%
3分 1.020回 99.660%
5分 612回 99.796%
10分 306回 99.898%
20分 153回 99.949%
60分 51回 99.983%

やはりリクエスト数が落ちると、短いキャッシュ時間ではほんのりキャッシュヒット率に差が出ますね。


1分に682回リクエスト、$T_{\rm Proc}$=0.1秒とすると

キャッシュ時間 1時間あたりのオリジンリクエスト キャッシュヒット率
なし 40,920回 0.000%
1分 120回 99.707%
2分 60回 99.853%
3分 40回 99.902%
5分 24回 99.941%
10分 12回 99.971%
20分 6回 99.985%
60分 2回 99.995%

リクエスト数が少ないですが、リクエストの処理時間が早ければキャッシュヒット率はとても良いですね。
リクエストの処理時間が早くすることは、キャッシュキーを無駄なく定義してリクエスト数を集中させるよりも効果があると言えます。


1分に17回リクエスト、$T_{\rm Proc}$=0.1秒とすると

キャッシュ時間 1時間あたりのオリジンリクエスト キャッシュヒット率
なし 1,020回 0.000%
1分 60回 94.118%
2分 30回 97.059%
3分 20回 98.039%
5分 12回 98.824%
10分 6回 99.412%
20分 3回 99.706%
60分 1回 99.902%

流石にここまでリクエスト数が少ないとキャッシュヒット率も変わってきますね。
とは言え、1分キャッシュでも60回までオリジンリクエスト数を抑えられるのであれば、そもそも相対的な数値を見る必要は無いと言えるかもしれません。

確かめられたこと

キャッシュキー毎のリクエスト数が十分多ければ例え1分であろうと効果は十分ある

リクエスト数が十分多ければ計算結果的には1分でもキャッシュヒット率が99%を超える。
逆に言うとキャッシュ時間を増やすだけでは、割合としてはそこまで変わらない。

ただし、「ちゃんとキャッシュされていれば」です。意図せずBYPASSとかになってたらダメですよ。3

キャッシュキー毎のリクエスト数が十分無いとキャッシュ時間が短くなるにつれ効果は薄れる

スッカスカなのにキャッシュ時間短めにするとキャッシュによる恩恵は小さくなっていきます。
これはつまり、キャッシュキーを過不足なく定義することにより、各キャッシュキー毎のリクエスト数を増やすことでキャッシュ効率を上げられるということでもあります。

サーバーの処理時間が短いとキャッシュヒット率が良くなる

「そもそも、オリジンリクエストがCDNに返ってくるまでの間にリクエストがドカドカ来るのが悪いので、さっさと返してCDNにキャッシュを作れば良いのだ。」
と考えるのです。
キャッシュ時間が短い時はよりその差が顕著に出てきます。

ど~~しても処理時間を減らすのが難しい!という場合は別のアプローチを検討しましょう。4

結論

キャッシュ時間を延ばせば良いってもんじゃない!

キャッシュ時間を設定した上で、更にオリジンリクエスト数を抑えたいならば、別のアプローチを検討すべき4でしょう。また、意図せずその設定が意味を為さなくなってしまっていないかも確認しなければなりません。3

また、画像等の静的コンテンツならともかく、動的コンテンツについてはそもそもキャッシュ時間を長めにして良い物と悪い物があります。5
やっぱり、ユーザーに対して常に最新のコンテンツを配信出来るに越したことはないのですから、キャッシュ時間の調整に関しては「やれたらやる。」程度に考えておけば良いと思います。

  1. 勿論、実際はその時のリクエストのばらつき具合にもよる。

  2. $\frac{N}{s} \times t \geq 1$という条件の意味
    キャッシュが効く時間の間、1回以上リクエストが来ればキャッシュする意味がある。
    例えば2分に1回しかリクエストが来ないのに、キャッシュ時間を1分にしていてはキャッシュ時間を設定する意味が無い。($\frac{N}{s} = 0.5$なので、キャッシュ時間$t = 2$分以上は無いと意味が無い。)
    ちなみに$\frac{N}{s} \times t < 1$の時、キャッシュが全く効かないので全リクエスト数=オリジンリクエスト数になる。すなわち、$R_{\rm Orig} = \lfloor 60 \times \frac{N}{s} \rfloor$回となる。

  3. キャッシュヒット率を上げるために何より最も重要なことをご覧ください 2

  4. キャッシュ時間の調整以外の方法をご覧ください 2

  5. コンテンツの更新を適切に反映するをご覧ください

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?