ElastiCache の遅延読み込みと書き込みスルーの違い ── キャッシュミスのときだけデータベースから読む

目次

概要

データベースへの読み込みが多いアプリケーションに Amazon ElastiCache を足すと、同じデータの読み込みをキャッシュで受け止めて、応答を速くし、データベースの負荷を下げられます。ただし、キャッシュは置いただけでは使われません。いつキャッシュに書き、いつキャッシュから読むかを、アプリケーションのコードで決める必要があります。

代表的な書き方(キャッシュ戦略)が、遅延読み込み(レイジーローディング) と 書き込みスルー です。遅延読み込みは「まずキャッシュを読み、無ければデータベースから読んでキャッシュに書く」、書き込みスルーは「データベースに書くたびにキャッシュも更新する」書き方です。

この記事では、2 つの戦略の処理の流れと、それぞれの長所・短所(古いデータ、使われないデータ)、TTL の役割を整理します。実践では、ElastiCache for Memcached と DynamoDB を使い、遅延読み込みでキャッシュミスとキャッシュヒットが起きる様子、データベースだけを更新したときに古い値が返る様子、書き込みスルーでそれが解消する様子を確かめます。

遅延読み込み:まずキャッシュ、無いときだけデータベースから読んでキャッシュに書く
遅延読み込み:まずキャッシュ、無いときだけデータベースから読んでキャッシュに書く
クラウドおさる

よく聞かれる値段は、手元の帳面(キャッシュ)に書いておけば、いちいちバナナ倉庫(データベース)まで走らずに済むでござる。問題は、いつ帳面に書くかでござるよ。

この記事のメリット

  • 遅延読み込みと書き込みスルーの処理の流れを、疑似コードで書けるようになる
  • 2 つの戦略の長所と短所(古いデータ、使われないデータ、書き込みの遅さ)を比べられるようになる
  • TTL で古いデータとキャッシュの肥大化を抑える考え方が分かる
  • ElastiCache のメトリクスでキャッシュのヒットとミスを確認できるようになる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。

クラウドおさる

基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

遅延読み込み(レイジーローディング)

遅延読み込みは、データが必要になったときに初めてキャッシュに載せる戦略です。

record_value = cache.get(record_key)
if record_value == NULL:                       # キャッシュミス
    record_value = db.query("SELECT Details FROM Records WHERE ID = ?", record_key)
    cache.set(record_key, record_value)        # 次に備えてキャッシュに書く
return record_value
  • キャッシュにあれば(キャッシュヒット)、データベースを読まずに返す
  • キャッシュに無ければ(キャッシュミス)、データベースから読み、キャッシュに書いてから返す

キャッシュを読まずにいきなりデータベースを読む書き方や、データベースへの書き込み(UPDATE)のたびにキャッシュを更新する書き方は、遅延読み込みではありません。

書き込みスルー

書き込みスルーは、データベースに書き込むたびにキャッシュも同じ値で更新する戦略です。

db.query("UPDATE Records SET Details = ? WHERE ID = ?", record_value, record_key)
cache.set(record_key, record_value)
遅延読み込みは読むときに、書き込みスルーは書くときにキャッシュを埋める
遅延読み込みは読むときに、書き込みスルーは書くときにキャッシュを埋める

長所と短所

項目遅延読み込み書き込みスルー
キャッシュに載るデータ実際に読まれたデータだけ書き込まれたデータすべて(読まれないものも)
キャッシュノードの障害致命的ではない(ミスが増えて遅くなるだけ)更新が載らない期間が生じる
キャッシュミスのときデータベースへの往復が増え、最初の読み込みが遅い書き込み済みのデータならミスは少ない
古いデータデータベースだけが更新されると、キャッシュに古い値が残るキャッシュも一緒に更新されるので古くなりにくい
書き込みの遅さ影響なし書き込みのたびにキャッシュへの書き込みも増える
クラウドおさる

遅延読み込みの帳面は、倉庫の値段が変わっても自分からは書き換わらぬのでござる。古い値段で売ってしまわぬよう、帳面の書き込みに期限(TTL)を付けておくのが肝でござるぞ。

TTL(有効期限)

キャッシュに書くときに TTL(有効期限)を付けると、期限が切れたキーは読み込もうとしても見つからないもの(キャッシュミス)として扱われ、次の読み込みでデータベースから新しい値を取り直します。

  • 遅延読み込みでは、古いデータが残り続ける期間の上限になる
  • 書き込みスルーでは、一度も読まれないデータがキャッシュを埋め続けるのを防ぐ

実際には、遅延読み込みと書き込みスルーを組み合わせ、TTL も付けて使うことが多くあります。

新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

実践

ハンズオンガイド7 ステップ画面 5 枚

コンソールの横に開いて、チェックしながら進めましょう。

ガイドを開く

別タブで開きます。チェックはこのブラウザに保存されます。

EC2 インスタンス dva-cache-app から、ElastiCache for Memcached のクラスター dva-cache-lab と DynamoDB の dva-cache-records(データベース役)を使います。用意済みの Python スクリプトで、遅延読み込みと書き込みスルーの動きを確かめます。

前提条件

  • リージョン: ap-northeast-1(東京)
  • 以下のリソースが作成済みであること

まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。

リソース種別リソース名内容作り方の参考
VPC・サブネットdva-cache-vpcパブリックサブネット 2 つ(1a / 1c)―
ElastiCache クラスターdva-cache-labMemcached、cache.t4g.micro × 1 ノード。SG で dva-cache-app-sg からの 11211 番ポートを許可Amazon ElastiCache でキャッシュを置いて読み込みを速くする(※この記事は Memcached を使う)
DynamoDB テーブルdva-cache-recordsパーティションキー record_id。rec-001〜rec-003 の 3 件(details に品名と値段)Amazon DynamoDB でテーブルを作り Lambda から読み書きする
EC2 インスタンスdva-cache-appAmazon Linux 2023。Session Manager で接続でき、/opt/cache-lab/ に下の 3 つのスクリプトと、キャッシュとテーブルへの接続を設定した common.py があるAmazon EC2 でインスタンスを起動しSSH接続する
スクリプト処理
lazy_get.py <キー>遅延読み込み。キャッシュを読み、無ければ DynamoDB から読んで TTL 300 秒でキャッシュに書く。HIT / MISS と処理時間を表示する
update_db.py <キー> <値>DynamoDB だけを更新する(キャッシュは触らない)
write_through.py <キー> <値>書き込みスルー。DynamoDB を更新し、キャッシュも同じ値で更新する

作成するリソース一覧

この実践では新しいリソースは作りません(キャッシュとテーブルの中身を読み書きします)。

手順 1: キャッシュクラスターを確かめる

AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに ElastiCache と入力し、「ElastiCache」を選択します。左側ナビゲーションの「Memcached キャッシュ」で dva-cache-lab を開き、ステータスが「Available」、エンジンが Memcached であることと、設定エンドポイント(dva-cache-lab.xxxxxx.cfg.apne1.cache.amazonaws.com:11211 の形)を確認します。スクリプトは、このクラスターのノードのエンドポイント(.0001. が入った名前)に接続するよう common.py に設定してあります。

ElastiCache の Memcached キャッシュ dva-cache-lab の詳細(ステータスとエンドポイント)
ElastiCache の Memcached キャッシュ dva-cache-lab の詳細(ステータスとエンドポイント)

手順 2: 遅延読み込みでキャッシュミスとヒットを見る

EC2 のコンソールで dva-cache-app を選択し、「接続」→「Session Manager」タブ →「接続」をクリックします。開いたターミナルで、次のコマンドを実行します。

cd /opt/cache-lab
export PYTHONWARNINGS=ignore
python3 lazy_get.py rec-001
python3 lazy_get.py rec-001
python3 lazy_get.py rec-001

export PYTHONWARNINGS=ignore は、Amazon Linux 2023 の Python 3.9 に対して boto3 が出すサポート終了の警告を表示しないためのものです(動作には影響しません)。

1 回目は MISS rec-001 -> banana: 100 yen (38.5 ms) ※データベースから読んでキャッシュに書いた、2 回目以降は HIT rec-001 -> banana: 100 yen (1.4 ms) のように表示されます(ミリ秒の値は実行のたびに変わります)。HIT のときはデータベースを読まないので、処理時間も短くなります。1 回目から HIT になった場合は、以前の実行の値がキャッシュに残っています。TTL の 300 秒が過ぎると MISS から始まります。

Session Manager の実行結果(1 回目が MISS、2 回目以降が HIT)
Session Manager の実行結果(1 回目が MISS、2 回目以降が HIT)

手順 3: データベースだけを更新して、古い値が返ることを見る

ほかのアプリケーションがデータベースの値段を変えた場面を再現します。

python3 update_db.py rec-001 "banana: 120 yen"
python3 lazy_get.py rec-001

データベースは banana: 120 yen に変わったのに、lazy_get.py は HIT rec-001 -> banana: 100 yen と古い値を返します。遅延読み込みでは、キャッシュに値が残っている間(TTL の 300 秒が過ぎるまで)、データベースの変更が反映されません。

Session Manager の実行結果(データベースを更新しても、キャッシュの古い値が HIT で返る)
Session Manager の実行結果(データベースを更新しても、キャッシュの古い値が HIT で返る)
クラウドおさる

倉庫の値段は 120 になったのに、帳面には 100 のままでござる。帳面を見るだけで倉庫に行かぬのが遅延読み込みの速さの秘密でござるが、裏を返せば、こういうずれも起きるのでござるな。

手順 4: 書き込みスルーで更新する

書き込みスルーで、データベースとキャッシュを一緒に更新します。

python3 write_through.py rec-001 "banana: 130 yen"
python3 lazy_get.py rec-001

今度は HIT rec-001 -> banana: 130 yen と、新しい値がキャッシュから返ります。書き込みのたびにキャッシュも更新したので、古い値が残りません。

Session Manager の実行結果(書き込みスルーの後は、新しい値が HIT で返る)
Session Manager の実行結果(書き込みスルーの後は、新しい値が HIT で返る)

手順 5: キャッシュのメトリクスを見る

ElastiCache のコンソールで dva-cache-lab を開き、「メトリクス」タブを選択します。メトリクスは数十個あるので、検索欄に Get と入力して絞り込みます。「Get ヒット」(GetHits、キャッシュヒットの数)と「Get ミス」(GetMisses、キャッシュミスの数)のグラフに、ここまでの操作が反映されています(グラフに点が出るまで数分かかります)。ヒットの割合が高いほど、キャッシュがデータベースの読み込みを肩代わりできています。

ElastiCache のメトリクス(Get ヒットと Get ミス)
ElastiCache のメトリクス(Get ヒットと Get ミス)
クラウドおさる

読むときに埋めるのが遅延読み込み、書くときに埋めるのが書き込みスルー。ずれを嫌うなら書き込みスルーを足し、TTL で古さに上限を付ける。試験では、疑似コードの順番で見分けるのでござる。

まとめ

戦略キャッシュに書くとき弱点補い方
遅延読み込み読み込みでキャッシュミスしたとき古いデータ、最初の読み込みが遅いTTL、書き込みスルーとの併用
書き込みスルーデータベースに書き込むたび読まれないデータでキャッシュが埋まる、書き込みが重くなるTTL
  • 遅延読み込みは「キャッシュを読む → 無ければデータベースを読む → キャッシュに書く」の順
  • 書き込みスルーは「データベースに書く → キャッシュも同じ値で更新する」
  • 遅延読み込みでは、データベースだけが更新されると、TTL が切れるまで古い値が返る
  • TTL は、古いデータが残る期間と、使われないデータがキャッシュを埋め続けることの両方を抑える
  • ElastiCache for Memcached では、GetHits・GetMisses のメトリクスでヒットとミスを確認できる

参照先

キャリア相談
クラウドおさる

独学の先に、AWS の仕事がある ── ジュニアおさるのキャリア相談

CLF には受かったけれど、次に何をすればいいのか分からない。独学で AWS を学ぶジュニアおさるの相談に、株式会社ジェニュイン代表の土肥が答えています。

  • ✓資格はゴールか、CLF の次に何から手を付けるか
  • ✓EC2 の次に作ってみる構成と、IaC・コスト管理
  • ✓実務経験ゼロでも、面接で話せる「これまで」の作り方
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次