TT Lab
はじめる
学ぶ 学習パス コース

Redisとキャッシュ

cache-asideを実装しヒット率を測る

TT Labで続きを見る

目標

cache-asideを自分で実装して、ミスとヒットのコストの差を数字で確認し、ネガティブキャッシュとバージョンキーによる無効化まで付けます。

なぜ重要なのか

cache-asideは最も一般的なパターンなので、コードはどこからでもコピーできます。本当に難しいのは細部です。書き込み時にキャッシュを更新するか削除するか、存在しないデータをキャッシュするか、そして全体を一度に無効化する必要があるとき何をするかです。1つ目。更新ではなく削除が正解である理由は、2つの書き込みがすれ違うとき、更新は古い値を残すことがありますが、削除はそうではないからです。2つ目。存在しないキーを繰り返し取得するトラフィックは、キャッシュを素通りして原本をそのまま叩きます。これをキャッシュ貫通といい、短いTTLのネガティブキャッシュで防ぎます。3つ目。商品カテゴリが丸ごと変わったとき、関連するキーをすべて探して消すのは、依存関係追跡の地獄です。バージョンキーは、それをバージョン番号を1つ上げる作業に変えます。

ステップ

  1. /opt/app/slowdb.pyを127.0.0.1:8151で起動します。GET /item/1が200を返し、GET /statsが{"queries":<n>}を返します。
  2. /root/ca/cache.pyにget_item(id)を作ります。キャッシュミスなら原本を取得して、item:<id>キーに300秒で保存します。/root/ca/miss.outにsource=origin ms=<정수>を書きます(プレースホルダーは整数です)。msは100以上である必要があります。
  3. 同じ項目をもう一度取得します。/root/ca/hit.outにsource=cache ms=<정수> origin_queries_delta=0を書きます(プレースホルダーは整数です)。msは50未満である必要があります。
  4. /root/ca/update.pyは、原本を更新したあとにキャッシュキーを削除します。ソースに、更新値をキャッシュに書き直すコードがあってはいけません。実行後、EXISTS item:1が0である必要があります。
  5. 存在しないitem:9999を取得すると原本が404を返すので、その結果を60秒の寿命でキャッシュします。2回目の取得で原本の取得数が増えてはならず、TTL item:9999が1以上60以下である必要があります。
  6. /root/ca/bench.pyで100回の取得(ユニークなキー20個)を行い、/root/ca/hitratio.txtにhits=<n> misses=<n> ratio=<소수>を書きます(プレースホルダーは小数です)。ratioは0.75以上である必要があります。
  7. キャッシュキーをv<버전>:item:<id>の形に変えて(プレースホルダーはバージョンです)、バージョンをver:itemキーで管理します。バージョンを上げたあとに取得すると、原本の取得数が増える必要があります。/root/ca/version.outにold_ver=<n> new_ver=<n> refetched=trueを書きます。

参考

遅い原本を起動する

/opt/app/slowdb.pyを127.0.0.1:8151で起動してください。GET /item/1が200を返し、GET /statsが{"queries":<n>}を返します。

/opt/app/slowdb.pyは、取得のたびにわざと時間をかけます。自分が受けた取得の数も教えてくれます。

キャッシュミスの経路を作る

/root/ca/cache.pyにget_item(id)を作ってください。キャッシュミスなら原本を取得して、item:<id>キーに300秒で保存します。/root/ca/miss.outにsource=origin ms=<정수>を書き(プレースホルダーは整数です)、msは100以上である必要があります。

キャッシュになければ原本に行って、キャッシュに入れて返します。最初の取得は遅くなるしかありません。

2回目の取得をキャッシュで処理する

同じ項目をもう一度取得してください。/root/ca/hit.outにsource=cache ms=<정수> origin_queries_delta=0を書き(プレースホルダーは整数です)、msは50未満である必要があります。

同じキーをもう一度取得したときは、原本に行ってはいけません。原本の取得数が増えていないか確認してください。

更新時にキャッシュを削除する

/root/ca/update.pyは、原本を更新したあとにキャッシュキーを削除してください。ソースに、更新値をキャッシュに書き直すコードがあってはいけません。実行後、EXISTS item:1が0である必要があります。

更新ではなく削除です。その理由は読み物にあります。次の取得が自然に最新を埋めます。

存在しないキーをネガティブキャッシュする

存在しないitem:9999を取得すると原本が404を返すので、その結果を60秒の寿命でキャッシュしてください。2回目の取得で原本の取得数が増えてはならず、TTL item:9999が1以上60以下である必要があります。

存在しないキーを繰り返し取得すると、毎回原本に行きます。短い寿命で「ない」もキャッシュしてください。

ヒット率を測る

/root/ca/bench.pyで100回の取得(ユニークなキー20個)を行い、/root/ca/hitratio.txtにhits=<n> misses=<n> ratio=<소수>を書いてください(プレースホルダーは小数です)。ratioは0.75以上である必要があります。

ヒットとミスをそれぞれ数えて、比率を出します。リクエストの分布によって値が変わります。

バージョンキーで全体を無効化する

キャッシュキーをv<버전>:item:<id>の形に変えて(プレースホルダーはバージョンです)、バージョンをver:itemキーで管理してください。バージョンを上げたあとに取得すると、原本の取得数が増える必要があります。/root/ca/version.outにold_ver=<n> new_ver=<n> refetched=trueを書きます。

キー名にバージョンを埋め込めば、バージョンを上げるだけで、古いキーを誰も探さなくなります。削除を自分でしなくてもよいのです。