- Firestore のドキュメントモデル(コレクション / ドキュメント / サブコレクション)、インデックスの仕組み、リアルタイムリスナー、エディションと無料枠
- Bigtable のアーキテクチャ(コンピュートとストレージの分離)と、性能を左右する行キー設計・ホットスポット回避
- Memorystore(Redis / Valkey)のティア構成と、キャッシュ・セッションストアとしての設計パターン
- エミュレータ(Firestore / Bigtable / Pub/Sub / Spanner)による課金ゼロのローカル開発ループ
- Cloud Storage・RDB・NoSQL・DWH を横断する「ストレージ選択の全体地図」で要件から製品を選ぶ
試験ガイド対応: セクション 1.3(ネットワーク、ストレージ、コンピューティング リソースの設計)、5.2(実装の管理 — 開発・運用環境とツールの理解。エミュレータは試験ガイドの明示トピック)
Firestore — ドキュメントモデルとリアルタイム同期
第 9 章のリレーショナルデータベースは「スキーマを先に決め、SQL で整合的に扱う」世界でした。本章はその外側、つまりスキーマレスな NoSQL とインメモリを扱います。1 つ目の Firestore は、自動スケーリング・高性能・開発のしやすさを掲げるサーバーレスの NoSQL ドキュメントデータベースです。サーバーアプリケーションからだけでなく、モバイル / Web クライアント SDK から直接読み書きできるのが最大の個性で、データの変更をクライアントへリアルタイムに通知できます。バックエンドを薄く保ちたいモバイルアプリやコラボレーションアプリの定番です。
コレクションとドキュメントの入れ子
Firestore にはテーブルも行もありません。データはドキュメント(キーと値のペアの集まり)に保存され、ドキュメントはコレクションに格納されます。値の型はブール値・数値・文字列・地理的座標・バイナリ blob・タイムスタンプ・配列・ネストしたオブジェクト(マップ)をサポートし、同じコレクション内のドキュメントがそれぞれ異なるフィールド構成を持ってもかまいません(スキーマレス)。コレクションとドキュメントは最初の書き込み時に暗黙的に作成され、事前の定義は不要です。
階層はサブコレクションで表現します。ドキュメントの下にコレクションをぶら下げる構造で、最大 100 階層までネストできます。1 ドキュメントのサイズ上限は 1 MiB(Standard エディション。2026-08 時点)と小さいので、画像などの大きなバイナリは 第 8 章の Cloud Storage に置き、Firestore にはその参照を持たせるのが定石です。
クエリとインデックス — 「自動」と「手動」
Firestore Standard エディションは、コレクション内ドキュメントの各フィールドに対して自動でインデックスを構築します(従来は単一フィールドインデックスと呼ばれていたものです)。単純な等価・範囲クエリはこれだけで動きます。一方、範囲比較を含む複合クエリや、別フィールドでの並べ替えには、複数フィールドを組み合わせた手動インデックス(従来の複合インデックス)を明示的に作る必要があります。既存インデックスで実行できないクエリを投げると、Firestore は不足しているインデックスを作成するためのリンク付きのエラーメッセージを返します。これは実務でもよく遭遇する挙動で、「つまずきポイント」で改めて取り上げます。逆に、検索に使わない長い文字列フィールドや TTL フィールドはインデックス除外を設定して書き込みコストを下げられます。
リアルタイムリスナーとクライアント直結
Firestore の代名詞が onSnapshot() によるリアルタイムリスナーです。リスナーを付けると、まず現在の内容のスナップショットが即座に届き(クエリの場合、既存ドキュメントすべてが added として通知されます)、以後は変更のたびに added / modified / removed の差分がコールバックに届きます。さらにレイテンシ補正という仕組みがあり、自分のローカル書き込みはバックエンドに送信される前にリスナーへ即時反映されます。未送信の変更は metadata.hasPendingWrites で判別できます。不要になったリスナーは unsubscribe() で必ずデタッチします。クライアント SDK は Web・Android・Apple プラットフォームに対応しており、クライアント直結の読み書きはセキュリティルールで保護します。
エディション・モード・無料枠
| 項目 | Standard エディション | Enterprise エディション |
|---|---|---|
| データアクセス | Native モード / Datastore モード(旧 Datastore 互換。サーバー向け) | Native モード / MongoDB 互換 API |
| クエリ | すべてのクエリにインデックスが必要 | インデックスの有無を問わず実行可能 |
| ドキュメント上限 | 1 MiB | 最大 16 MiB(MongoDB 互換時) |
エディションとモードはデータベース作成時に選び、後から変更できません。本書のハンズオンでは Standard + Native モードを使います。無料枠(2026-08 時点)は Standard で 1 日あたり読み取り 50,000 回・書き込み 20,000 回・削除 20,000 回、保存 1 GiB、下り 10 GiB/月。ただし無料枠が適用されるのは1 プロジェクトにつき 1 データベースだけです。
Bigtable — 行キーがすべてのワイドカラムストア
Bigtable は数十億行・数千列にスケールするワイドカラム型のキーバリューストアで、テラバイト〜ペタバイト級のデータと大量書き込みを低レイテンシで受け止めます。テーブルは行キーでソートされたキーバリューマップで、各行は行キーという単一のインデックスだけを持ちます。列は列ファミリーにグループ化され、使われていない列は領域を消費しません(スパース)。セカンダリインデックスや SQL の JOIN に頼る設計はできず、その代わりに桁違いのスループットが手に入る——この割り切りが Bigtable の本質です。時系列・IoT テレメトリ・金融データ・マーケティングデータが代表ワークロードで、第 18 章のケーススタディでも車両テレメトリの受け皿として登場します。
アーキテクチャ — コンピュートとストレージの分離
スループットはノード数に比例してスケールします。ストレージは SSD(既定)と低コストの HDD から選べ、クラスタをもう 1 つ追加するとレプリケーションが自動で始まります。整合性はトポロジで決まります——単一クラスタなら強整合、複数クラスタでは既定で結果整合です。この「レプリカを増やすと整合性の既定が変わる」関係は試験でも問われる論点です。
行キー設計 — ホットスポットを避ける
Bigtable の性能は行キー設計がすべてです。原則は「実行するクエリから逆算してキーを設計する」こと。行はキーの辞書順に並び、連続するキー範囲(タブレット)を各ノードが分担するため、キーの先頭部分が書き込みの分散を決めます。
避けるべきアンチパターンは、タイムスタンプで始まるキー(図の通り単一ノードへの集中=ホットスポットを生む)、連番の数値 ID(同じ理由)、キー全体のハッシュ化(分散はするが辞書順の範囲読み取りという利点を失う)、頻繁に更新される単一の識別子です。主な設計上の上限(2026-08 時点)は、行キー 4 KB 以下・1 セル 10 MB 以下推奨・1 行の値の合計は 100 MB 未満を推奨(ハード上限は 256 MB)・列ファミリー約 100 個・1 インスタンス 1,000 テーブルまで。関連する列は同じ列ファミリーにまとめ、ガベージコレクション(保持期間)はファミリー単位で設定されるため保持要件が違うデータはファミリーを分けます。ファミリー名は転送データに含まれるので短くします。マルチテナントでは、テーブルを分けるのではなく1 つのテーブルで行キーに顧客プレフィックスを付けるのが推奨です。
互換性とツール
Bigtable は Java 向け Apache HBase クライアントの拡張をサポートし、既存の HBase エコシステムから移行しやすいのが伝統的な強みです。加えて GoogleSQL for Bigtable による SQL クエリにも対応し、Cassandra や DynamoDB からの移行ガイドも用意されています。CLI は cbt(Go クライアントライブラリ製)で、ハンズオン 10-3 で使います。ただし cbt はスマートリトライやエラー処理を実装していないため、本番用途ではクライアントライブラリを使うのが公式の推奨です。
Memorystore — インメモリキャッシュとセッションストア
Memorystore はフルマネージドのインメモリデータストアで、サブミリ秒のデータアクセスを提供します。エンジンとして Redis と、オープンソースの Valkey を選べます(クラスタ対応の Memorystore for Redis Cluster もあります)。代表ユースケースはデータベースの前段のキャッシュ、セッション管理、ゲームのリーダーボード、ストリーム処理です。接続はプライベート IP 経由で、同一 VPC の Compute Engine・GKE・Cloud Run などから接続します(一部のサーバーレス環境は VPC への接続経路の構成が必要です)。
Memorystore for Redis のティア
| 項目 | Basic ティア | Standard ティア |
|---|---|---|
| レプリケーション | なし | ゾーン間レプリケーション |
| 自動フェイルオーバー | なし | あり(高速フェイルオーバー) |
| SLA | — | 99.9%(2026-08 時点) |
| リードレプリカ | — | 最大 5 個 |
| 容量 | 1〜300 GB(M1: 1–4 / M2: 5–10 / M3: 11–35 / M4: 36–100 / M5: 101–300) | |
Basic ティアはレプリケーションもフェイルオーバーもないため、インスタンス障害でデータが消えても困らない純粋なキャッシュ専用と割り切ります。セッションのように消えるとユーザー影響が出るデータは Standard ティアを選びます。Valkey 版はクラスタモードの有効 / 無効を選べ、各シャードは 1 プライマリ + 最大 5 レプリカで構成され、レプリカはゾーンに分散して可用性と読み取りスループットを高めます(対応バージョンは Valkey 7.2 / 8.0 / 9.0、および 9.1(プレビュー)、2026-08 時点)。
キャッシュアサイドパターン
アーキテクチャ上の重要な使い道がもう 1 つあります。第 4 章の MIG や 第 7 章の Cloud Run でオートスケールするには、各インスタンスが状態を持たない(ステートレスである)必要がありました。セッション状態を Memorystore へ外出しするのは、既存アプリをステートレス化してスケールさせる定番の手筋で、試験でも頻出です。
ローカル開発とエミュレータ — 課金ゼロの開発ループ
データベースを学ぶたびに実インスタンスを作っていては、課金と待ち時間で開発ループが重くなります。gcloud CLI は主要データプロダクトのローカルエミュレータを提供しており、試験ガイドのセクション 5.2 でも Bigtable・Datastore・Spanner・Pub/Sub・Firestore のエミュレータが明示されています。共通の性質は 3 つ——①データはメモリ内のみで、停止すると消える、②環境変数を設定するとクライアントライブラリが自動的にエミュレータへ接続する、③本番用途では使えない(認証や一部 API が未実装)。
| プロダクト | 起動コマンド | 環境変数 | 既定エンドポイント |
|---|---|---|---|
| Firestore | gcloud emulators firestore start | FIRESTORE_EMULATOR_HOST | 127.0.0.1:8080 |
| Bigtable | gcloud beta emulators bigtable start | BIGTABLE_EMULATOR_HOST | localhost:8086 |
| Pub/Sub | gcloud beta emulators pubsub start | PUBSUB_EMULATOR_HOST | 起動ログに表示(env-init で自動設定可) |
| Spanner | gcloud emulators spanner start | SPANNER_EMULATOR_HOST | gRPC 9010 / REST 9020 |
それぞれ癖もあります。Firestore エミュレータは --edition フラグで Standard / Enterprise を選べます。Spanner エミュレータは事前に gcloud components install cloud-spanner-emulator が必要で、TLS・認証・IAM は非対応です。Bigtable エミュレータはインスタンスやクラスタの管理 API を持ちません(テーブル操作はできます)。Pub/Sub エミュレータは $(gcloud beta emulators pubsub env-init) で環境変数を自動設定でき、メッセージは無期限に保持されます。CI パイプライン(第 16 章)にエミュレータを組み込めば、クラウド資格情報なしで統合テストを回せます。
Standard エディションの Firestore データベースを東京リージョンに作り、REST API で都市データを書き込み・読み取りします。所要 20 分。費用: 無料枠内(1 日 50,000 読み取り / 20,000 書き込みに対し、本ハンズオンは数十回)。Cloud Shell での実行を前提とします(ローカルの gcloud でも可)。
- API を有効化し、データベースを作成する(PROJECT_ID は
gcloud config get-value projectで確認できる自分のプロジェクト ID)。
gcloud services enable firestore.googleapis.com
gcloud firestore databases create \
--location=asia-northeast1 \
--edition=standard \
--type=firestore-native
- アクセストークンとプロジェクト ID を変数に取り、ドキュメントを作成する。
PROJECT_ID=$(gcloud config get-value project)
TOKEN=$(gcloud auth print-access-token)
curl -s -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"fields": {"name": {"stringValue": "Tokyo"}, "pref": {"stringValue": "13"}}}' \
"https://firestore.googleapis.com/v1/projects/${PROJECT_ID}/databases/(default)/documents/cities?documentId=tokyo"
成功すると、作成されたドキュメントの JSON(name にフルパス、fields、createTime / updateTime)が返ります。コレクション cities は事前定義なしで暗黙に作成されました。
- 単一ドキュメントの取得と、コレクション内ドキュメントの一覧を確認する。
curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://firestore.googleapis.com/v1/projects/${PROJECT_ID}/databases/(default)/documents/cities/tokyo"
curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://firestore.googleapis.com/v1/projects/${PROJECT_ID}/databases/(default)/documents/cities"
コンソールの場合は「Firestore」→ データベースを選ぶと、コレクションとドキュメントをブラウザで閲覧・編集できます。
後片付け: ドキュメントを削除し、データベースも削除します。
curl -s -X DELETE -H "Authorization: Bearer ${TOKEN}" \
"https://firestore.googleapis.com/v1/projects/${PROJECT_ID}/databases/(default)/documents/cities/tokyo"
gcloud firestore databases delete --database='(default)' --quiet
10-1 と同じ操作を、今度はクラウド資源を一切作らずエミュレータで再現します。所要 10 分。費用: 0 円(Cloud Shell 内で完結)。
- エミュレータを起動する(既定で 127.0.0.1:8080 で待ち受けます)。ターミナルはこのプロセスに占有されるので、Cloud Shell の「+」で 2 つ目のタブを開いて続けます。
gcloud emulators firestore start
- 2 つ目のタブから、10-1 と同じ REST 呼び出しをエミュレータへ向ける。ローカルエミュレータは認証を検証しないので、トークンもプロジェクトの実在も不要(ここではダミーの demo-pca を使用)。
curl -s -X POST -H "Content-Type: application/json" \
-d '{"fields": {"name": {"stringValue": "Tokyo"}}}' \
"http://127.0.0.1:8080/v1/projects/demo-pca/databases/(default)/documents/cities?documentId=tokyo"
curl -s "http://127.0.0.1:8080/v1/projects/demo-pca/databases/(default)/documents/cities"
- アプリからも同じように使えることを確認する。環境変数を設定すると、サーバークライアントライブラリは自動的にエミュレータへ接続します。
export FIRESTORE_EMULATOR_HOST="127.0.0.1:8080"
- テストデータの全消去は専用エンドポイントで一発です。
curl -s -X DELETE \
"http://127.0.0.1:8080/emulator/v1/projects/demo-pca/databases/(default)/documents"
データはメモリ内のみで、エミュレータを再起動すると消えます(永続化されません)。
後片付け: 環境変数を戻し、エミュレータを停止します(起動タブで Ctrl+C でも可)。
unset FIRESTORE_EMULATOR_HOST
curl -s -d '' http://127.0.0.1:8080/shutdown
Bigtable の実インスタンスはノード課金で学習向きではないので、エミュレータ + cbt CLI で「行キーの辞書順」と「プレフィックス走査」を体感します。所要 15 分。費用: 0 円。
- cbt CLI を導入し(導入済みならスキップ)、エミュレータを起動する。起動後は別タブで作業します。
gcloud components install cbt
gcloud beta emulators bigtable start
- 別タブで環境変数と cbt の設定ファイルを用意する。cbt は Go クライアントライブラリ製なので、BIGTABLE_EMULATOR_HOST が設定されていればエミュレータに接続します。エミュレータはインスタンスを管理しないため、プロジェクト名・インスタンス名はダミーでかまいません。
export BIGTABLE_EMULATOR_HOST=localhost:8086
echo project = demo-pca > ~/.cbtrc
echo instance = demo-instance >> ~/.cbtrc
- テーブルと列ファミリーを作り、「デバイス ID + タイムスタンプ」形式の行キーでセンサーデータを書き込む。
cbt createtable sensor-data
cbt createfamily sensor-data stats
cbt set sensor-data dev001#202608160900 stats:temp=21.9
cbt set sensor-data dev001#202608161000 stats:temp=22.4
cbt set sensor-data dev002#202608160900 stats:temp=19.8
cbt ls sensor-data
- プレフィックス走査で「dev001 の時系列だけ」を読む。行キーは辞書順に並ぶため、デバイス ID を先頭に置いたことで 1 台分の時系列が連続領域から時刻順に返ります。
cbt read sensor-data prefix=dev001
cbt lookup sensor-data dev001#202608161000
出力には行キーごとに stats:temp のセル値とタイムスタンプが表示されます。prefix=dev001 の結果に dev002 の行が含まれないこと、2 つの行が時刻順に並ぶことを確認してください。これが図 10-3 の「OK 側」の設計です。
後片付け: テーブルを消し、設定を戻してエミュレータを停止します(起動タブで Ctrl+C)。
cbt deletetable sensor-data
unset BIGTABLE_EMULATOR_HOST
rm ~/.cbtrc
つまずきポイント
理解度チェック
Q1. Google Cloud でローカルエミュレータが提供される主なデータプロダクトを挙げ、アプリケーションをエミュレータへ向ける共通の仕組みを説明してください。
Firestore・Bigtable・Pub/Sub・Spanner(および Datastore)です。各エミュレータ専用の環境変数(FIRESTORE_EMULATOR_HOST / BIGTABLE_EMULATOR_HOST / PUBSUB_EMULATOR_HOST / SPANNER_EMULATOR_HOST)を設定すると、クライアントライブラリが自動的にエミュレータへ接続します。データはメモリ内のみで再起動で消え、本番用途には使えません。試験ガイド 5.2 の明示トピックです。
Q2. Bigtable の行キーをタイムスタンプで始めてはいけないのはなぜですか。時系列データの正しい設計は?
行は行キーの辞書順に並び、連続するキー範囲を各ノードが分担します。タイムスタンプ先頭だと新規書き込みが常に「最新」の範囲に落ち、単一ノードに集中してホットスポットになります。デバイス ID など高カーディナリティの値を先頭に置き、タイムスタンプを後ろに付ければ、書き込みは分散しつつデバイス単位の時系列をプレフィックス走査で読めます。
Q3. Memorystore for Redis の Basic ティアと Standard ティアの違いを 3 点挙げてください。
① Standard はゾーン間レプリケーションを持つが Basic は持たない。② Standard は自動フェイルオーバーがあり 99.9% の SLA が付くが、Basic にはどちらもない。③ Standard は最大 5 個のリードレプリカで読み取りをスケールできる。したがって Basic は消えてよいキャッシュ専用、セッション等は Standard を選びます。
Q4.(試験形式)製造業の企業が 100 万台の IoT センサーから毎秒数百万件のテレメトリを取り込み、デバイス単位の直近データをミリ秒レイテンシで読み出したい。適切なデータストアは?
A. Firestore B. Bigtable C. Cloud SQL D. BigQuery
B。ペタバイト級の時系列・大量書き込み・低レイテンシのキー読み出しは Bigtable の設計目標そのものです。A の Firestore はモバイル / Web 向けドキュメント DB で、この規模の時系列書き込みの受け皿には向きません。C の Cloud SQL は単一プライマリの垂直スケールでこの書き込み量を捌けません。D の BigQuery は SQL 分析用の DWH であり、ミリ秒のキー単位読み出しの要件に合いません(分析用途に Bigtable と組み合わせるのは好手です)。
Q5.(試験形式)スタートアップがモバイルアプリを開発中。ユーザー間でデータをリアルタイムに同期し、サーバー管理なしで自動スケールするデータベースを求めている。最適な選択は?
A. Memorystore for Redis B. Bigtable C. Firestore D. AlloyDB for PostgreSQL
C。モバイル / Web SDK 直結・リアルタイムリスナー・サーバーレスの自動スケールという要件は Firestore の代名詞です。A はインメモリキャッシュで永続ストアの主役ではありません。B はモバイル SDK 直結やリアルタイム通知の仕組みを持たず、ノードのプロビジョニングも必要です。D はリレーショナル DB でインスタンス管理が伴い、リアルタイム同期は標準機能ではありません。
まとめ — ストレージ選択の全体地図と次章へ
第 8 章から本章まででストレージ系プロダクトが出揃いました。試験で最も問われるのは個々の機能ではなく「この要件ならどれか」の判断です。全体を 1 枚の地図にまとめます。
- Firestore はサーバーレスのドキュメント DB。コレクション / ドキュメントの入れ子、自動インデックス + 手動インデックス、リアルタイムリスナー、モバイル / Web SDK 直結が骨格。無料枠は 1 プロジェクト 1 データベース
- Bigtable はワイドカラムの大量書き込み・時系列特化。コンピュート(ノード)とストレージ(Colossus)が分離し、ノード数でスループットが線形に伸びる。性能は行キー設計で決まり、タイムスタンプ先頭はホットスポットの元
- Memorystore はインメモリ。Basic は消えてよいキャッシュ専用、Standard はレプリケーション + 自動フェイルオーバー + 99.9% SLA。セッション外出しはステートレス化の定石
- Firestore / Bigtable / Pub/Sub / Spanner にはエミュレータがあり、環境変数でクライアントを切り替えて課金ゼロで開発・CI ができる(試験ガイド 5.2)
次の第 11 章では、本章の地図で「SQL で大規模分析」に分岐した先——BigQuery と、データを流し込む Pub/Sub・Dataflow によるデータ分析基盤を扱います。