データをどこに置くか
読了目安 約3分
プロセス内メモリ、共有キャッシュ、データベースという 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 ページ返しています。
- 画像をデータベースの BLOB から読んでいるとき、画像のためだけの転送量は毎秒何 MB ですか
- nginx がファイルを直接返すようにすると、データベースの転送量はどうなりますか
答えを見る
1 は 150 KB × 10 枚 × 100 ページ = 毎秒 150 MB です。 データベースはクエリの結果もこの同じ道で返すので、画像がふさいだぶんだけクエリが待たされます。 2 は 0 です。画像の配信がアプリとデータベースから完全に消え、両者はクエリに専念できます。