𝕏 f B! L
案件・求人数 12,345
案件を探す(準備中) エージェントを探す(準備中) お役立ち情報 ログイン
案件・求人数 12,345
Google Cloud Spanner実践ガイド|グローバル分散データベースの設計・運用・コスト最適化

Google Cloud Spanner実践ガイド|グローバル分散データベースの設計・運用・コスト最適化

Google CloudCloud Spannerデータベース分散システムSES
目次
⚡ 3秒でわかる!この記事のポイント
  • Cloud SpannerはRDBの整合性とNoSQLのスケーラビリティを両立した唯一のグローバル分散DB
  • ホットスポットを回避するスキーマ設計とインターリーブテーブルの活用が性能の鍵
  • Processing Unitベースの柔軟なスケーリングとコスト最適化でTCOを50%削減できるケースもある

「RDBの強い整合性が必要だが、グローバルにスケールしたい」「NoSQLの水平スケーリングが欲しいが、トランザクションも必要」——従来のデータベースでは解決が困難だったこの課題を、Cloud Spannerはリレーショナル・分散・スケーラブルの3つを同時に実現することで解決します。

この記事はGoogle Cloud完全攻略シリーズの第17回として、Cloud Spannerの設計・運用・コスト最適化をSESエンジニア向けに実践的に解説します。

この記事でわかること
  • Cloud Spannerのアーキテクチャと他DBとの違い
  • ホットスポットを回避するスキーマ設計のベストプラクティス
  • インターリーブテーブルによるパフォーマンス最適化
  • グローバル分散構成の設計パターン
  • Processing Unitベースのコスト最適化テクニック
  • SES案件での活用シナリオと求められるスキル

Cloud Spannerとは — 他DBとの違い

Cloud Spannerの位置づけ

Cloud Spannerは、Googleが開発したグローバル分散リレーショナルデータベースです。従来のRDB(MySQL/PostgreSQL)とNoSQL(DynamoDB/Bigtable)の両方の利点を持つ、ユニークな存在です。

特性MySQL/PostgreSQLDynamoDB/BigtableCloud Spanner
スキーマ厳密なスキーマスキーマレス厳密なスキーマ
トランザクションACID制限付きグローバルACID
スケーリング垂直(スケールアップ)水平(自動)水平(自動)
整合性強い整合性(単一ノード)結果整合性強い外部整合性(グローバル)
SQLフルSQL限定的フルSQL(ANSI準拠)
可用性SLA99.95%99.99%99.999%(マルチリージョン)

TrueTimeによるグローバル整合性

Cloud Spannerの核心技術はTrueTime APIです。Googleのデータセンターに設置された原子時計とGPSレシーバーにより、ナノ秒精度のグローバル時刻同期を実現しています。これにより、世界中のどのノードに書き込んでも、完全な整合性(外部整合性)が保証されます。

TrueTimeの仕組み:
┌──────────┐    ┌──────────┐    ┌──────────┐
│ 東京      │    │ アイオワ   │    │ ロンドン   │
│ ノードA   │    │ ノードB   │    │ ノードC   │
└─────┬────┘    └─────┬────┘    └─────┬────┘
      │               │               │
      └───────┬───────┘───────┬───────┘
              │               │
        ┌─────┴─────┐  ┌─────┴─────┐
        │ 原子時計   │  │  GPS      │
        │ サーバー群 │  │ レシーバー │
        └───────────┘  └───────────┘

     グローバル外部整合性を保証

スキーマ設計のベストプラクティス

主キー設計 — ホットスポットの回避

Cloud Spannerで最も重要なのが主キー設計です。連番(AUTO_INCREMENT相当)を主キーにすると、新しいデータが常に同じノードに集中する「ホットスポット」が発生します。

❌ アンチパターン: 連番主キー

-- NG: 連番は常に末尾のスプリットに書き込みが集中
CREATE TABLE Users (
  UserId INT64 NOT NULL,
  Name STRING(100),
  Email STRING(255),
) PRIMARY KEY (UserId);

✅ 推奨: UUIDまたはビット反転ID

-- OK: UUIDで書き込みを分散
CREATE TABLE Users (
  UserId STRING(36) NOT NULL DEFAULT (GENERATE_UUID()),
  Name STRING(100),
  Email STRING(255),
  CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
) PRIMARY KEY (UserId);

✅ 推奨: 複合キーによるシャーディング

-- OK: ShardIdで書き込みを16分割
CREATE TABLE Orders (
  ShardId INT64 NOT NULL,
  OrderId STRING(36) NOT NULL,
  CustomerId STRING(36) NOT NULL,
  TotalAmount NUMERIC,
  Status STRING(20),
  CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
) PRIMARY KEY (ShardId, OrderId);

インターリーブテーブル — 親子データの局所性最適化

Cloud Spanner固有の機能である**インターリーブ(INTERLEAVE IN PARENT)**は、親子関係のデータを物理的に同じスプリットに配置し、JOIN性能を劇的に向上させます。

-- 親テーブル: Users
CREATE TABLE Users (
  UserId STRING(36) NOT NULL,
  Name STRING(100),
  Email STRING(255),
) PRIMARY KEY (UserId);

-- 子テーブル: Orders(Usersにインターリーブ)
CREATE TABLE Orders (
  UserId STRING(36) NOT NULL,
  OrderId STRING(36) NOT NULL,
  TotalAmount NUMERIC,
  CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
) PRIMARY KEY (UserId, OrderId),
  INTERLEAVE IN PARENT Users ON DELETE CASCADE;

-- 孫テーブル: OrderItems(Ordersにインターリーブ)
CREATE TABLE OrderItems (
  UserId STRING(36) NOT NULL,
  OrderId STRING(36) NOT NULL,
  ItemId STRING(36) NOT NULL,
  ProductName STRING(200),
  Quantity INT64,
  UnitPrice NUMERIC,
) PRIMARY KEY (UserId, OrderId, ItemId),
  INTERLEAVE IN PARENT Orders ON DELETE CASCADE;

この設計により、あるユーザーの注文一覧と注文詳細を取得するクエリが、単一ノード内のディスクアクセスで完結します。

Cloud Spannerアーキテクチャとスキーマ設計パターン

セカンダリインデックスの設計

-- NULL_FILTERED: NULLを含む行をインデックスから除外(スペース節約)
CREATE NULL_FILTERED INDEX OrdersByStatus
  ON Orders (Status, CreatedAt DESC);

-- STORING: カバリングインデックスでテーブルアクセスを回避
CREATE INDEX OrdersByCustomer
  ON Orders (CustomerId)
  STORING (TotalAmount, Status, CreatedAt);

クエリの最適化

実行プランの分析

-- クエリの実行プランを確認
EXPLAIN ANALYZE
SELECT u.Name, o.OrderId, o.TotalAmount
FROM Users u
JOIN Orders o ON u.UserId = o.UserId
WHERE u.UserId = @user_id
ORDER BY o.CreatedAt DESC
LIMIT 10;

パフォーマンスチューニングのポイント

1. ステイルリード(Stale Read)の活用

強い整合性が不要な読み取りには、ステイルリードを使用してパフォーマンスを向上させます。

# Python (google-cloud-spanner)でのステイルリード
import datetime
from google.cloud import spanner

instance = spanner_client.instance("my-instance")
database = instance.database("my-database")

# 15秒前のスナップショットで読み取り(レプリカから読む可能性あり)
with database.snapshot(
    exact_staleness=datetime.timedelta(seconds=15)
) as snapshot:
    results = snapshot.execute_sql(
        "SELECT Name, Email FROM Users WHERE UserId = @id",
        params={"id": user_id},
        param_types={"id": spanner.param_types.STRING},
    )
    for row in results:
        print(f"Name: {row[0]}, Email: {row[1]}")

2. バッチ処理の最適化

# ミューテーションのバッチ書き込み
with database.batch() as batch:
    batch.insert(
        table="Users",
        columns=["UserId", "Name", "Email", "CreatedAt"],
        values=[
            [str(uuid4()), "田中太郎", "[email protected]", spanner.COMMIT_TIMESTAMP],
            [str(uuid4()), "佐藤花子", "[email protected]", spanner.COMMIT_TIMESTAMP],
            # ... 最大20,000ミューテーションまでバッチ可能
        ],
    )

3. パーティション化DMLによる大量更新

-- パーティション化DMLで大量更新を効率的に実行
-- (サーバー側で自動的にパーティション分割される)
UPDATE Orders
SET Status = 'archived'
WHERE CreatedAt < TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 365 DAY)
  AND Status = 'completed';

グローバル分散構成の設計

リージョン構成の選択

Cloud Spannerは3つの構成タイプを提供します。

構成タイプ可用性SLAレイテンシ用途
リージョナル99.99%最小単一リージョンのワークロード
マルチリージョン99.999%やや高い高可用性が必要な本番環境
カスタム99.999%設定による特定地域の要件に対応

マルチリージョン構成の例

# マルチリージョンインスタンスの作成
gcloud spanner instances create global-app-db \
  --config=nam-eur-asia1 \
  --description="グローバルアプリケーションDB" \
  --processing-units=1000

# データベースの作成
gcloud spanner databases create app \
  --instance=global-app-db \
  --ddl='CREATE TABLE Users (
    UserId STRING(36) NOT NULL DEFAULT (GENERATE_UUID()),
    Name STRING(100),
    Region STRING(20),
    CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
  ) PRIMARY KEY (UserId)'

リーダー配置の最適化

書き込み性能を最適化するために、リーダーリージョンを適切に設定します。

# リーダーリージョンの確認
gcloud spanner instances describe global-app-db --format="value(config)"

# カスタム構成でリーダーリージョンを東京に設定
gcloud spanner instance-configs create custom-asia-config \
  --base-config=nam-eur-asia1 \
  --replicas=location=asia-northeast1,type=READ_WRITE \
  --replicas=location=us-central1,type=READ_WRITE \
  --replicas=location=europe-west1,type=READ_ONLY \
  --leader-region=asia-northeast1

コスト最適化

Processing Unitによる柔軟なスケーリング

Cloud Spannerは2024年以降、ノード単位ではなくProcessing Unit(PU)単位で課金されます。最小100 PU(≒0.1ノード)から利用可能で、小規模なワークロードでもコスト効率よく利用できます。

# Processing Unitの設定(100 PU = 最小構成)
gcloud spanner instances create small-app-db \
  --config=regional-asia-northeast1 \
  --description="小規模アプリDB" \
  --processing-units=100

# スケールアップ(負荷に応じて)
gcloud spanner instances update small-app-db \
  --processing-units=300

オートスケーリングの設定

# オートスケーラーの設定
gcloud spanner instances update my-instance \
  --autoscaling-min-processing-units=100 \
  --autoscaling-max-processing-units=2000 \
  --autoscaling-high-priority-cpu-target=65 \
  --autoscaling-storage-target=80

コスト見積もりの目安

構成Processing Units月額概算(東京リージョン)
最小構成100 PU約$65/月
小規模本番300 PU約$195/月
中規模1000 PU (1ノード)約$650/月
大規模3000 PU (3ノード)約$1,950/月
マルチリージョン3000 PU約$5,850/月

※ストレージ料金($0.30/GB/月)は別途

コスト管理の詳細はGoogle Cloud Monitoring&Loggingガイドも参照してください。

アプリケーション統合パターン

Go言語でのCRUD実装

package main

import (
    "context"
    "fmt"
    "log"

    "cloud.google.com/go/spanner"
    "google.golang.org/api/iterator"
)

func createUser(ctx context.Context, client *spanner.Client, name, email string) error {
    _, err := client.Apply(ctx, []*spanner.Mutation{
        spanner.InsertOrUpdate("Users",
            []string{"UserId", "Name", "Email", "CreatedAt"},
            []interface{}{spanner.GenericColumnValue{Type: spanner.NullString{}, Value: nil}, name, email, spanner.CommitTimestamp},
        ),
    })
    return err
}

func getUserOrders(ctx context.Context, client *spanner.Client, userID string) error {
    stmt := spanner.Statement{
        SQL: `SELECT u.Name, o.OrderId, o.TotalAmount, o.CreatedAt
              FROM Users u
              JOIN Orders o ON u.UserId = o.UserId
              WHERE u.UserId = @userId
              ORDER BY o.CreatedAt DESC
              LIMIT 20`,
        Params: map[string]interface{}{"userId": userID},
    }

    iter := client.Single().Query(ctx, stmt)
    defer iter.Stop()

    for {
        row, err := iter.Next()
        if err == iterator.Done {
            break
        }
        if err != nil {
            return err
        }
        var name, orderID string
        var amount spanner.NullFloat64
        var createdAt spanner.NullTime
        if err := row.Columns(&name, &orderID, &amount, &createdAt); err != nil {
            return err
        }
        fmt.Printf("Order: %s, Amount: %.2f\n", orderID, amount.Float64)
    }
    return nil
}

Spring Boot (Java)での統合

// Spring Data Cloud Spannerでの使用例
@Entity(tableName = "Users")
public class User {
    @PrimaryKey
    @Column(name = "UserId")
    private String userId;

    @Column(name = "Name")
    private String name;

    @Column(name = "Email")
    private String email;

    @Column(name = "CreatedAt")
    @CommitTimestamp
    private Timestamp createdAt;

    @Interleaved
    private List<Order> orders;
}

@Repository
public interface UserRepository extends SpannerRepository<User, String> {
    List<User> findByEmailContaining(String email);

    @Query("SELECT * FROM Users WHERE CreatedAt > @since")
    List<User> findRecentUsers(@Param("since") Timestamp since);
}

Cloud SQL/AlloyDBからの移行

移行判断フローチャート

Cloud Spannerを選ぶべきケース:

  • 99.999%の可用性が必要
  • グローバルな書き込み分散が必要
  • 水平スケーリングが必要(数TB以上のデータ)
  • ACID トランザクションが必須

Cloud SQL/AlloyDBを選ぶべきケース:

  • 単一リージョンで十分
  • コストを最小限に抑えたい
  • PostgreSQL/MySQL互換が重要
  • 小規模(〜数百GB)

Cloud SQLの詳細はCloud SQL最適化ガイドを参照してください。

データ移行ツール

# Harbourbridge(OSS)を使った移行
harbourbridge -driver=postgres \
  -source="host=localhost dbname=mydb user=admin password=secret" \
  -target-profile="instance=my-spanner,dbname=mydb"

# Dataflow を使った大規模移行
gcloud dataflow jobs run postgres-to-spanner \
  --gcs-location=gs://dataflow-templates/latest/Postgres_to_Cloud_Spanner \
  --parameters \
    instanceId=my-instance,\
    databaseId=my-database,\
    jdbcUrl=jdbc:postgresql://source-db:5432/mydb,\
    table=Users

SES案件でのCloud Spanner活用

Cloud Spannerのスキルが求められるSES案件は、主に大規模なグローバルサービスや金融系システムです。2026年現在、Cloud Spanner経験のあるエンジニアの月額単価は80〜120万円が相場です。

求められるスキルセット:

  • スキーマ設計(ホットスポット回避、インターリーブ)
  • クエリ最適化(実行プラン分析、ステイルリード)
  • グローバル分散構成の設計
  • 移行計画の策定と実行
  • コスト見積もりと最適化

まとめ

Cloud Spannerは、リレーショナルDBの整合性とNoSQLのスケーラビリティを兼ね備えた唯一無二のデータベースサービスです。

Cloud Spanner活用で押さえるべきポイント:

  • 主キー設計でホットスポットを回避(UUID or 複合キー)
  • インターリーブテーブルで親子データの局所性を最適化
  • ステイルリードで読み取り性能を向上(整合性要件に応じて)
  • Processing Unitベースの柔軟なスケーリングでコストを最適化
  • グローバル分散構成はリーダーリージョンの配置が鍵

SESエンジニアとしてCloud Spannerのスキルを身につけることで、高単価な大規模案件への参画機会が大きく広がるでしょう。

SES案件をお探しですか?

SES記事をもっと読む →
🏗️

SES BASE 編集長

SES業界歴10年以上のメンバーが在籍する編集チーム。SES企業での営業・エンジニア経験、フリーランス独立経験を持つメンバーが、業界のリアルな情報をお届けします。

📊 業界データに基づく記事制作 🔍 IPA・経済産業省データ参照 💼 SES実務経験者が執筆・監修