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

データをどこに置くか

読了目安 約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 ページ返しています。

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

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