データをどこに置くか
読了目安 約3分
プロセス内メモリ、共有キャッシュ、データベースという 3 つの置き場所を、速さ・一貫性・消え方で使い分けます。
この章の目次
データの置き場所は、大きく 3 つあります。 アプリ自身のメモリ、共有のキャッシュサーバー、そしてデータベースです。
共有のキャッシュサーバーは、覚えた結果をアプリとは別の 1 台に集め、全サーバーがネットワーク越しに参照する置き場所です。 memcached や Valkey が定番です。
どれに置くかは、コンピュータにおけるデータの操作とコスト感 で見た段の上り下りです。
| 置き場所 | 読み出し 1 回 | 中身 | 再起動すると |
|---|---|---|---|
| プロセス内のメモリ | 100 ns 前後 | サーバーごとに別 | 消える |
| 共有のキャッシュサーバー | 200 µs 前後 | 全サーバーで 1 つ | 消える |
| データベース | 200 µs + クエリ処理 | 全サーバーで 1 つ | 残る |
本物は 1 つに決める
同じデータを 2 か所に置くなら、どちらを本物とみなすかを先に決めます。 本物とみなす側を正と呼びます(「DB を正とする」という言い方をします)。
この表で正にできるのは、再起動しても残るデータベースだけです。 メモリ側の 2 つは「消えても正から作り直せるコピー」として使います。 この線を守っているかぎり、キャッシュはいつ消えても壊れません。
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 です。画像の配信がアプリとデータベースから完全に消え、両者はクエリに専念できます。