🔩 ねじき教室 Go と Web の教室

データをどこに置くか

読了目安 約3分

プロセス内メモリ、共有キャッシュ、データベースという 3 つの置き場所を、速さ・一貫性・消え方で使い分けます。

30秒でつかむ 速いほど近く、確実なほど遠くに置く
速いほど近く、確実なほど遠くに置くプロセス内メモリ、共有キャッシュ、DBの順に、共有しやすさと永続性が増えます。1プロセス内最速だが消える2共有キャッシュ複数台で使う3DB正として残す
  1. プロセス内 最速だが消える
  2. 共有キャッシュ 複数台で使う
  3. DB 正として残す
この章の目次

データの置き場所は、大きく 3 つあります。 アプリ自身のメモリ、共有のキャッシュサーバー、そしてデータベースです。

共有のキャッシュサーバーは、覚えた結果をアプリとは別の 1 台に集め、全サーバーがネットワーク越しに参照する置き場所です。 memcached や Valkey が定番です。

どれに置くかは、コンピュータにおけるデータの操作とコスト感 で見た段の上り下りです。

置き場所読み出し 1 回中身再起動すると
プロセス内のメモリ100 ns 前後サーバーごとに別消える
共有のキャッシュサーバー200 µs 前後全サーバーで 1 つ消える
データベース200 µs + クエリ処理全サーバーで 1 つ残る

キャッシュとデータベースの役割分担

データベースは永続化層として、ユーザーデータなど消えては困る構造化データを置く場所です。 プロセス内メモリと共有キャッシュは、サーバーの再起動で消えます。 消えて困るデータをそちらに置くわけにはいかないので、キャッシュにはデータベースへ問い合わせ直せば同じ内容を再現できるコピーだけを置きます。

ISUCON では、ベンチマーカーが最初に初期化処理を呼びます。 キャッシュをデータベースから作り直せない設計は、この時点で落ちます。

画像はデータベースに入れない

画像のような大きなデータを、テーブルの 1 列(BLOB という型)に入れる設計があります。 こうすると、画像を読むたびに数百 KB がデータベースとの通信を占有します。 クエリのために空けておきたい道を、画像の運搬がふさぎます。

画像はファイルとしてディスクに置き、Web サーバー(nginx など)に直接返させます。 静的なファイルの配信は Web サーバーの得意技で、アプリとデータベースは 1 バイトも触らずに済みます。

データベースから画像を追い出すのは ISUCON の定番です(練習問題 private-isu が典型)。移行では「ファイルを書き終えてから、投稿をデータベースに反映する」の順序を守ってください。逆にすると、投稿は見えるのに画像がまだ無い一瞬ができ、そこにアクセスが滑り込みます。

試してみよう

1 枚 150 KB の画像が 1 ページに 10 枚載り、毎秒 100 ページ返しています。

  1. 画像をデータベースの BLOB から読んでいるとき、画像のためだけの転送量は毎秒何 MB ですか
  2. nginx がファイルを直接返すようにすると、データベースの転送量はどうなりますか
答えを見る

1 は 150 KB × 10 枚 × 100 ページ = 毎秒 150 MB です。 データベースはクエリの結果もこの同じ道で返すので、画像がふさいだぶんだけクエリが待たされます。 2 は 0 です。画像の配信がアプリとデータベースから完全に消え、両者はクエリに専念できます。