CockroachDB

CockroachDB 総合ガイド — 機能・アーキテクチャ・設定の全容

本ドキュメントは CockroachDB の全体像を俯瞰し、アーキテクチャの深部から運用上の設定例までを網羅的に解説する。対象読者はデータベース技術に一定の知見を持つエンジニアを想定している。


1. はじめに — CockroachDB とは何か

1.1 概要

CockroachDB は、Cockroach Labs 社が開発した 分散型 NewSQL データベース である。Google Spanner の設計思想に強く影響を受けており、以下の特徴を兼ね備えている。

  • 強一貫性(Strong Consistency): すべてのトランザクションが Serializable 分離レベルで実行される
  • 水平スケーラビリティ: ノードを追加するだけで自動的にデータが再分散される
  • 地理的分散: 複数リージョンにまたがるクラスタで低レイテンシと高可用性を両立する
  • PostgreSQL 互換 SQL: ワイヤプロトコルレベルで PostgreSQL と互換性があり、既存のドライバやツールが利用可能
  • 自己修復: ノード障害時にレプリカを自動的に再配置し、クラスタの健全性を維持する

1.2 誕生の背景

CockroachDB の名前は「ゴキブリ」に由来する。これはゴキブリの驚異的な生存能力を比喩的に表現したもので、「何があっても生き残るデータベース」というビジョンを体現している。

創業者の Spencer Kimball、Peter Mattis、Ben Darnell は元 Google のエンジニアであり、Google Spanner と F1 での経験を基に、オープンソースでアクセス可能な分散データベースを構築することを目指した。2014 年にプロジェクトが開始され、2017 年に CockroachDB 1.0 がリリースされた。

1.3 ライセンスとエディション

CockroachDB は以下のエディションで提供されている。

エディションライセンス主な用途
CockroachDB CoreBusiness Source License (BSL)開発・テスト・小規模本番
CockroachDB Enterprise商用ライセンス大規模本番環境
CockroachDB Serverlessマネージドサービスサーバーレスで利用
CockroachDB Dedicatedマネージドサービス専用クラスタでの利用
CockroachDB Self-Hosted商用ライセンスオンプレミス環境

注意: BSL は 3 年経過後に Apache 2.0 に変換されるが、変換前はサードパーティによる商用 DBaaS 提供が制限される。

1.4 主要な利用シナリオ

CockroachDB が特に適しているユースケースは以下のとおりである。

  1. グローバル分散アプリケーション: 複数リージョンにデータを配置し、ユーザーの地理的位置に基づいて低レイテンシのアクセスを提供する
  2. 高可用性が求められるシステム: 金融、EC、決済など、ダウンタイムが許容されないシステム
  3. マイクロサービスアーキテクチャ: 各サービスが独立したスキーマを持ちながらも、強一貫性のあるトランザクションを実行する
  4. リレーショナルデータのスケールアウト: シャーディングの複雑さなしに水平スケーリングを実現する
  5. マルチクラウド・ハイブリッドクラウドデプロイ: クラウドベンダーロックインを避けつつ、複数のクラウド環境にまたがるデプロイ

2. アーキテクチャの全体像

2.1 レイヤード・アーキテクチャ

CockroachDB は以下の 4 層構造で設計されている。

┌─────────────────────────────────────────────┐
│              SQL Layer                       │
│  (パーサー, オプティマイザ, エグゼキューター)       │
├─────────────────────────────────────────────┤
│          Transaction Layer (KV)              │
│  (トランザクション管理, MVCC, タイムスタンプ)      │
├─────────────────────────────────────────────┤
│          Distribution Layer                  │
│  (Range 管理, Raft コンセンサス, リース)          │
├─────────────────────────────────────────────┤
│            Storage Layer                     │
│  (Pebble ストレージエンジン, SST, WAL)           │
└─────────────────────────────────────────────┘

SQL Layer

SQL レイヤーは PostgreSQL 互換のインターフェースを提供する。クライアントからの SQL クエリを受け取り、以下の処理を順次実行する。

  1. パース: SQL 文を抽象構文木(AST)に変換
  2. 名前解決: テーブル名・カラム名をシステムカタログから解決
  3. 型チェック: 式の型推論と型強制
  4. 最適化: コストベースオプティマイザ(CBO)による実行計画の生成
  5. 実行: 分散実行エンジン(DistSQL)または単一ノード実行

Transaction Layer

KV(Key-Value)レイヤーとも呼ばれ、以下の責務を持つ。

  • MVCC(Multi-Version Concurrency Control): 各データに対して複数のバージョンをタイムスタンプ付きで保持する
  • トランザクション管理: Serializable 分離レベルでのトランザクション実行を保証する
  • タイムスタンプの割り当て: HLC(Hybrid Logical Clock)を使用してトランザクションのタイムスタンプを管理する
  • ロック管理: Write Intent(書き込み意図)を用いた楽観的ロック機構

Distribution Layer

分散レイヤーは、データの分散と複製を管理する。

  • Range: データは 512 MiB 単位の Range に分割される(デフォルト値)
  • Raft コンセンサス: 各 Range は Raft プロトコルで複製され、強一貫性が保証される
  • Leaseholder: 各 Range にはリースホルダーが割り当てられ、読み書きのコーディネーションを行う
  • メタデータ管理: Range のキーマッピングは 2 レベルのメタデータ Range で管理される

Storage Layer

ストレージレイヤーはデータの永続化を担当する。

  • Pebble: Go で実装された LSM(Log-Structured Merge)ツリーベースのストレージエンジン(RocksDB から移行済み)
  • WAL(Write-Ahead Log): クラッシュリカバリのための先行書き込みログ
  • SST(Sorted String Table): コンパクションされたデータファイル

2.2 ノードの構成

各 CockroachDB ノードは独立したプロセスとして動作し、以下のコンポーネントを含む。

┌─────────────────────────────────────────┐
│              CockroachDB Node            │
├──────────┬──────────┬───────────────────┤
│  Store 1 │  Store 2 │   Store N         │
│ (Disk 1) │ (Disk 2) │  (Disk N)         │
├──────────┴──────────┴───────────────────┤
│  SQL Gateway  │  DistSQL Processor      │
├───────────────┼─────────────────────────┤
│  Raft Engine  │  Gossip Protocol        │
├───────────────┼─────────────────────────┤
│  gRPC Server  │  HTTP Admin UI          │
└───────────────┴─────────────────────────┘
  • Store: 各ディスクに対応するストレージ単位。1 ノードに複数の Store を持てる
  • SQL Gateway: クライアント接続を受け付け、SQL を処理する
  • DistSQL Processor: 分散クエリの部分処理を担当する
  • Raft Engine: Range レプリカ間のコンセンサスを管理する
  • Gossip Protocol: クラスタ内のノード情報を交換する

2.3 クラスタの起動例

3 ノードのローカルクラスタを起動する例を以下に示す。

# ノード1(初期ノード)
cockroach start \
  --insecure \
  --store=node1 \
  --listen-addr=localhost:26257 \
  --http-addr=localhost:8080 \
  --join=localhost:26257,localhost:26258,localhost:26259

# ノード2
cockroach start \
  --insecure \
  --store=node2 \
  --listen-addr=localhost:26258 \
  --http-addr=localhost:8081 \
  --join=localhost:26257,localhost:26258,localhost:26259

# ノード3
cockroach start \
  --insecure \
  --store=node3 \
  --listen-addr=localhost:26259 \
  --http-addr=localhost:8082 \
  --join=localhost:26257,localhost:26258,localhost:26259

# クラスタの初期化(最初の1回のみ)
cockroach init --insecure --host=localhost:26257

2.4 セキュアモードでの起動

本番環境では TLS 証明書を使用したセキュアモードで起動する。

# CA 証明書の作成
cockroach cert create-ca \
  --certs-dir=certs \
  --ca-key=my-safe-directory/ca.key

# ノード証明書の作成(各ノードに対して実行)
cockroach cert create-node \
  localhost \
  node1.example.com \
  --certs-dir=certs \
  --ca-key=my-safe-directory/ca.key

# クライアント証明書の作成
cockroach cert create-client \
  root \
  --certs-dir=certs \
  --ca-key=my-safe-directory/ca.key

# セキュアモードでの起動
cockroach start \
  --certs-dir=certs \
  --store=node1 \
  --listen-addr=node1.example.com:26257 \
  --http-addr=node1.example.com:8080 \
  --join=node1.example.com:26257,node2.example.com:26257,node3.example.com:26257

3. データの分散とレプリケーション

3.1 Range — データ分散の基本単位

CockroachDB では、すべてのデータはキーバリュー(KV)ペアとして内部的に管理され、キーの昇順にソートされた連続する KV ペアの集合が Range と呼ばれる単位に分割される。

  • デフォルトサイズ: 512 MiB(range_max_bytes で設定可能)
  • 最小サイズ: Range が小さすぎる場合はマージされる(range_min_bytes、デフォルト 128 MiB)
  • 自動分割: Range がサイズ上限を超えると自動的に 2 つに分割される
  • 自動マージ: Range が最小サイズを下回り、隣接 Range との合計がサイズ上限内であればマージされる
-- Range の設定確認
SHOW ZONE CONFIGURATION FOR DATABASE mydb;

-- Range サイズの変更
ALTER DATABASE mydb CONFIGURE ZONE USING
  range_min_bytes = 134217728,  -- 128 MiB
  range_max_bytes = 536870912;  -- 512 MiB

3.2 キーのエンコーディング

SQL のテーブルデータは以下のようにキーにエンコードされる。

/Table/<table_id>/<index_id>/<primary_key_columns>/<column_family_id>

例えば、users テーブル(table_id=52)のプライマリキーが id=100 の行は以下のようなキーになる。

/Table/52/1/100/0

この仕組みにより、同一テーブル・同一インデックスのデータは物理的に近接して配置され、範囲スキャンが効率的に行える。

3.3 レプリケーション

各 Range は Raft コンセンサスプロトコル を使用して複数のノードにレプリケートされる。

  • デフォルトレプリカ数: 3(num_replicas で設定可能)
  • レプリカの種類:
    • Voting Replica(投票レプリカ): Raft の投票に参加する。リーダー選出に関与
    • Non-Voting Replica(非投票レプリカ): データのコピーは持つが投票には参加しない。読み取りの地理的分散に利用
-- レプリカ数の変更
ALTER DATABASE mydb CONFIGURE ZONE USING
  num_replicas = 5;

-- 非投票レプリカの設定(マルチリージョン構成時)
ALTER DATABASE mydb CONFIGURE ZONE USING
  num_voters = 3,
  num_replicas = 5;  -- 5 - 3 = 2 が非投票レプリカ

3.4 Raft コンセンサスプロトコル

Raft は分散システムにおけるコンセンサスアルゴリズムであり、CockroachDB の強一貫性を支える核心的な技術である。

Raft の基本動作

          ┌────────────────┐
          │   Raft Leader   │
          │   (Range R1)    │
          └───────┬────────┘
             ┌────┴────┐
             ▼         ▼
    ┌──────────────┐ ┌──────────────┐
    │ Raft Follower│ │ Raft Follower│
    │  (Replica 2) │ │  (Replica 3) │
    └──────────────┘ └──────────────┘

書き込みフロー:
1. クライアントが Leaseholder にリクエスト送信
2. Leaseholder が Raft リーダーに提案
3. リーダーが全フォロワーにログエントリを送信
4. 過半数(majority)が ACK を返すとコミット
5. コミット完了をクライアントに返却

Raft の設定パラメータ

-- Raft 関連のクラスタ設定
SET CLUSTER SETTING kv.raft.command.max_size = '64 MiB';
SET CLUSTER SETTING kv.raft_log.disable_synchronization_unsafe = false;

-- Raft のスナップショット転送レート
SET CLUSTER SETTING kv.snapshot_rebalance.max_rate = '64 MiB';
SET CLUSTER SETTING kv.snapshot_recovery.max_rate = '64 MiB';

3.5 Leaseholder

各 Range の Leaseholder は、その Range に対するすべての読み取りと書き込みのコーディネーションを行うレプリカである。

  • リース期間: デフォルト 6 秒(kv.range_lease.expiration_renewal_fraction で制御)
  • リースの自動移動: CockroachDB はアクセスパターンに基づいてリースホルダーを自動的に移動させる
  • Follower Read: 特定の条件下では、Leaseholder 以外のレプリカからの読み取りが可能(後述)
-- Leaseholder の確認
SELECT range_id, lease_holder, replicas
FROM [SHOW RANGES FROM TABLE mydb.users];

-- 特定のノードにリースを優先配置
ALTER TABLE users CONFIGURE ZONE USING
  lease_preferences = '[[+region=us-east1]]';

3.6 データの再バランシング

ノードの追加・削除時、CockroachDB は自動的にデータを再バランスする。

-- リバランスのレート制限設定
SET CLUSTER SETTING kv.snapshot_rebalance.max_rate = '64 MiB';

-- ストア間のリバランス閾値
SET CLUSTER SETTING kv.allocator.load_based_rebalancing = 'leases and replicas';

-- QPS ベースのリバランス閾値
SET CLUSTER SETTING kv.allocator.qps_rebalance_threshold = 0.1;

3.7 制約(Constraints)によるデータ配置制御

ゾーン設定を使用して、データの物理的な配置を制御できる。

-- ノードのロカリティ設定(起動時)
-- cockroach start --locality=region=us-east1,zone=us-east1-a ...

-- 特定リージョンへの制約
ALTER TABLE sensitive_data CONFIGURE ZONE USING
  constraints = '[+region=us-east1]';

-- 特定リージョンからの排除
ALTER TABLE non_eu_data CONFIGURE ZONE USING
  constraints = '[-region=eu-west1]';

-- 複数制約の組み合わせ
ALTER TABLE global_data CONFIGURE ZONE USING
  constraints = '{
    "+region=us-east1": 2,
    "+region=eu-west1": 2,
    "+region=ap-southeast1": 1
  }';

4. SQL レイヤーと PostgreSQL 互換性

4.1 PostgreSQL ワイヤプロトコル互換

CockroachDB は PostgreSQL のワイヤプロトコル(v3.0)と互換性があり、psql やあらゆる PostgreSQL ドライバを使用して接続できる。

# psql での接続
psql "postgresql://root@localhost:26257/defaultdb?sslmode=disable"

# cockroach sql コマンドでの接続
cockroach sql --insecure --host=localhost:26257

4.2 対応する SQL 機能

CockroachDB は標準的な SQL 機能の多くをサポートしている。

データ定義言語(DDL)

-- テーブル作成
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    username STRING NOT NULL UNIQUE,
    email STRING NOT NULL,
    created_at TIMESTAMPTZ DEFAULT now(),
    profile JSONB,
    INDEX idx_email (email),
    INDEX idx_created (created_at DESC),
    INVERTED INDEX idx_profile (profile)
);

-- パーティション付きテーブル(リージョン別)
CREATE TABLE orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    region STRING NOT NULL,
    customer_id UUID NOT NULL REFERENCES users(id),
    amount DECIMAL(10, 2) NOT NULL,
    status STRING DEFAULT 'pending',
    created_at TIMESTAMPTZ DEFAULT now(),
    INDEX idx_customer (customer_id),
    INDEX idx_status_region (region, status)
) PARTITION BY LIST (region) (
    PARTITION us_east VALUES IN ('us-east'),
    PARTITION us_west VALUES IN ('us-west'),
    PARTITION eu VALUES IN ('eu-west', 'eu-central')
);

-- Computed Column と部分インデックス
CREATE TABLE products (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name STRING NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    tax_rate DECIMAL(5, 4) DEFAULT 0.08,
    total_price DECIMAL(10, 2) AS (price * (1 + tax_rate)) STORED,
    is_active BOOL DEFAULT true,
    INDEX idx_active_products (name) WHERE is_active = true
);

データ型

CockroachDB がサポートする主なデータ型は以下のとおりである。

カテゴリデータ型
数値INT, FLOAT, DECIMAL, SERIAL
文字列STRING, VARCHAR, CHAR, BYTES
日時DATE, TIME, TIMESTAMP, TIMESTAMPTZ, INTERVAL
論理BOOL
ネットワークINET
UUIDUUID
JSONJSONB
配列ARRAY (例: INT[], STRING[])
地理空間GEOMETRY, GEOGRAPHY
EnumENUM (ユーザー定義型)
ビット列BIT, VARBIT

JSON サポート

-- JSONB 型の操作
INSERT INTO users (username, email, profile)
VALUES (
    'alice',
    'alice@example.com',
    '{"age": 30, "interests": ["coding", "music"], "address": {"city": "Tokyo"}}'
);

-- JSON パスによるクエリ
SELECT username, profile->'address'->>'city' AS city
FROM users
WHERE profile @> '{"interests": ["coding"]}';

-- Inverted Index を使った効率的な JSON 検索
SELECT * FROM users
WHERE profile @> '{"address": {"city": "Tokyo"}}';

-- JSON の更新
UPDATE users
SET profile = profile || '{"verified": true}'
WHERE username = 'alice';

4.3 コストベースオプティマイザ(CBO)

CockroachDB はコストベースオプティマイザを使用して最適な実行計画を選択する。

-- 実行計画の確認
EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com';

-- 詳細な実行計画(コスト付き)
EXPLAIN (VERBOSE) SELECT * FROM users WHERE email = 'alice@example.com';

-- 実際の実行統計
EXPLAIN ANALYZE SELECT * FROM users
JOIN orders ON users.id = orders.customer_id
WHERE orders.status = 'completed';

-- 統計情報の手動更新
CREATE STATISTICS users_stats FROM users;

-- 統計情報の自動収集設定
SET CLUSTER SETTING sql.stats.automatic_collection.enabled = true;
SET CLUSTER SETTING sql.stats.automatic_collection.min_stale_rows = 500;

4.4 DistSQL — 分散クエリ実行

DistSQL は、クエリをデータが存在するノードに分散して実行するフレームワークである。

-- DistSQL の実行計画を確認
EXPLAIN (DISTSQL) SELECT region, COUNT(*), SUM(amount)
FROM orders
GROUP BY region;

-- DistSQL の有効/無効(セッション単位)
SET distsql = on;   -- 強制的に DistSQL を使用
SET distsql = off;  -- DistSQL を無効化
SET distsql = auto; -- オプティマイザが自動選択(デフォルト)

DistSQL の処理フロー:

Client
  │
  ▼
Gateway Node (SQL Layer)
  │ クエリの解析・最適化
  ▼
Distributed Plan 生成
  │
  ├──▶ Node 1: TableReader (Range 1-3)  ──▶ Aggregator
  ├──▶ Node 2: TableReader (Range 4-6)  ──▶ Aggregator
  └──▶ Node 3: TableReader (Range 7-9)  ──▶ Aggregator
                                              │
                                              ▼
                                        Final Aggregator
                                         (Gateway Node)
                                              │
                                              ▼
                                           Client

4.5 PostgreSQL との非互換事項

CockroachDB は PostgreSQL と高い互換性を持つが、以下の相違点に注意が必要である。

機能PostgreSQLCockroachDB
デフォルト分離レベルRead CommittedSerializable
SERIALシーケンシャルランダム(unique_rowid())
スキーマ変更即時反映オンラインスキーマ変更(非同期)
ストアドプロシージャPL/pgSQL 完全対応限定的サポート
トリガー完全対応限定的サポート
XML 型対応非対応
拡張機能(Extension)豊富限定的(PostGIS 一部対応)
テンポラリテーブル完全対応対応(制限あり)
-- CockroachDB でのシーケンス(PostgreSQL 互換)
CREATE SEQUENCE user_id_seq;
CREATE TABLE legacy_users (
    id INT PRIMARY KEY DEFAULT nextval('user_id_seq'),
    name STRING NOT NULL
);

-- ただし分散環境ではシーケンスはボトルネックになりうるため
-- UUID の使用が推奨される
CREATE TABLE recommended_users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name STRING NOT NULL
);

5. トランザクションモデル

5.1 Serializable 分離レベル

CockroachDB は業界で最も厳格な Serializable 分離レベルをデフォルトで提供する。これは、すべてのトランザクションがあたかもシリアルに(1 つずつ順番に)実行されたかのような結果を保証する。

-- トランザクションの基本構文
BEGIN;
  UPDATE accounts SET balance = balance - 100 WHERE id = 1;
  UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

-- 明示的な分離レベル指定(CockroachDB では常に Serializable)
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  -- ...
COMMIT;

-- セーブポイント
BEGIN;
  INSERT INTO orders (customer_id, amount) VALUES ('uuid-1', 50.00);
  SAVEPOINT my_savepoint;
  INSERT INTO order_items (order_id, product_id, qty) VALUES ('uuid-2', 'uuid-3', 5);
  -- エラーが発生した場合
  ROLLBACK TO SAVEPOINT my_savepoint;
  -- 別の処理を試行
  INSERT INTO order_items (order_id, product_id, qty) VALUES ('uuid-2', 'uuid-4', 3);
COMMIT;

5.2 MVCC(Multi-Version Concurrency Control)

CockroachDB は MVCC を使用して並行トランザクションを管理する。各書き込みは新しいバージョンを作成し、読み取りは適切なタイムスタンプのバージョンを参照する。

Key: /Table/52/1/100

Timeline:
t=100  →  value_v1 (committed)
t=200  →  value_v2 (committed)
t=300  →  value_v3 (write intent - transaction in progress)
                    ↓
           Transaction Record: PENDING
  • Write Intent(書き込み意図): コミット前の書き込みは Intent として記録される
  • Transaction Record: 各トランザクションの状態(PENDING、COMMITTED、ABORTED)を追跡する
  • ガベージコレクション: 不要になった古いバージョンは GC によって削除される
-- GC の設定
ALTER DATABASE mydb CONFIGURE ZONE USING
  gc.ttlseconds = 86400;  -- 24 時間(デフォルト 14400 = 4 時間)

-- MVCC のガベージコレクション状態確認
SELECT * FROM crdb_internal.zones;

5.3 Hybrid Logical Clock(HLC)

CockroachDB は HLC を使用してトランザクションのタイムスタンプを管理する。HLC は物理クロックと論理クロックを組み合わせたもので、以下の特性を持つ。

HLC Timestamp = (物理時間, 論理カウンタ)

例:
  1617235200000000001.0000000001
  ├── 物理時間(ナノ秒)─┘    └── 論理カウンタ
  • 物理クロック: ノードの OS クロック(NTP で同期)
  • 論理カウンタ: 同一物理時間内での因果順序を保証
  • クロックスキュー許容値: デフォルト 500ms(--max-offset で設定)
# クロックスキュー許容値の設定(起動時オプション)
cockroach start \
  --max-offset=500ms \
  # ... その他のオプション
-- 現在の HLC タイムスタンプ確認
SELECT cluster_logical_timestamp();

-- クラスタ内のクロックオフセット確認
SELECT node_id, clock_offset_ns / 1000000 AS offset_ms
FROM crdb_internal.kv_node_status;

5.4 トランザクションの競合処理

並行トランザクション間で競合が発生した場合、CockroachDB は以下の戦略で処理する。

Read-Write 競合

Transaction A: READ key X at t=100
Transaction B: WRITE key X at t=90 (Intent)

→ Transaction A は B の完了を待つか、B を PUSH する
  - B が完了していない場合: A は B のタイムスタンプを進める(timestamp push)
  - B がコミット済みの場合: A はリトライする

Write-Write 競合

Transaction A: WRITE key X at t=100 (Intent)
Transaction B: WRITE key X at t=200 (Intent)

→ Transaction B は A の完了を待つ
  - A がコミットした場合: B は正常に進行
  - A がアボートした場合: B は A の Intent をクリーンアップして進行

5.5 トランザクションのリトライ

Serializable 分離レベルでは、トランザクションのリトライが発生することがある。CockroachDB は 自動リトライクライアントサイドリトライ の 2 つのメカニズムを提供する。

-- 自動リトライ(単一ステートメント、暗黙トランザクション)
-- CockroachDB が内部的にリトライする
INSERT INTO users (username, email) VALUES ('bob', 'bob@example.com');

-- クライアントサイドリトライ(明示的トランザクション)
-- アプリケーション側でリトライロジックを実装する必要がある

Go 言語でのリトライ実装例:

func executeTx(ctx context.Context, db *sql.DB, fn func(*sql.Tx) error) error {
    for retries := 0; retries < maxRetries; retries++ {
        tx, err := db.BeginTx(ctx, nil)
        if err != nil {
            return err
        }

        err = fn(tx)
        if err == nil {
            return tx.Commit()
        }

        _ = tx.Rollback()

        // リトライ可能なエラーかどうか確認
        if pqErr, ok := err.(*pq.Error); ok {
            if pqErr.Code == "40001" { // serialization_failure
                continue
            }
        }
        return err
    }
    return fmt.Errorf("transaction failed after %d retries", maxRetries)
}

5.6 Read Committed 分離レベル(v23.1+)

CockroachDB v23.1 以降では、Read Committed 分離レベルもサポートされるようになった。これにより、PostgreSQL からの移行がより容易になった。

-- セッション単位での分離レベル変更
SET default_transaction_isolation = 'read committed';

-- トランザクション単位での指定
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
  SELECT * FROM accounts WHERE id = 1;
  UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

-- クラスタ全体のデフォルト変更
SET CLUSTER SETTING sql.txn.default_isolation_level = 'read committed';

注意: Read Committed では Serializable よりもリトライが少なくなるが、ファントムリードや非再現読み取りが発生する可能性がある。


6. マルチリージョンとジオパーティショニング

6.1 マルチリージョン概要

CockroachDB のマルチリージョン機能は、地理的に分散したクラスタでデータのレイテンシ、可用性、およびコンプライアンス要件を制御するための高レベル抽象化を提供する。

-- データベースをマルチリージョンとして設定
ALTER DATABASE mydb SET PRIMARY REGION "us-east1";
ALTER DATABASE mydb ADD REGION "us-west1";
ALTER DATABASE mydb ADD REGION "eu-west1";

-- リージョン情報の確認
SHOW REGIONS FROM DATABASE mydb;

6.2 テーブルのロカリティ設定

マルチリージョンデータベースでは、テーブルに対して 3 種類のロカリティを設定できる。

REGIONAL BY TABLE(デフォルト)

テーブル全体のデータが特定のリージョンに最適化される。

-- テーブルをホームリージョンに配置
ALTER TABLE config_settings SET LOCALITY REGIONAL BY TABLE IN PRIMARY REGION;

-- 特定のリージョンに配置
ALTER TABLE eu_users SET LOCALITY REGIONAL BY TABLE IN "eu-west1";

REGIONAL BY ROW

行ごとに異なるリージョンにデータを配置する。

-- REGIONAL BY ROW テーブルの作成
CREATE TABLE user_profiles (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_region crdb_internal_region NOT NULL DEFAULT gateway_region()::crdb_internal_region,
    username STRING NOT NULL,
    email STRING NOT NULL,
    data JSONB
) LOCALITY REGIONAL BY ROW AS user_region;

-- 各行のリージョンは user_region カラムで決まる
INSERT INTO user_profiles (user_region, username, email)
VALUES
    ('us-east1', 'alice', 'alice@example.com'),
    ('eu-west1', 'bob', 'bob@example.com'),
    ('us-west1', 'charlie', 'charlie@example.com');

-- ローカルリージョンのデータへのクエリは低レイテンシ
SELECT * FROM user_profiles WHERE user_region = 'us-east1';

GLOBAL

すべてのリージョンから低レイテンシで読み取り可能。書き込みは高レイテンシ。

-- GLOBAL テーブル(読み取り頻度が高く、書き込み頻度が低いデータに適する)
ALTER TABLE reference_data SET LOCALITY GLOBAL;

-- 例: 通貨マスタ、国コード、設定テーブルなど
CREATE TABLE currency_rates (
    currency_code STRING PRIMARY KEY,
    rate_to_usd DECIMAL(10, 6) NOT NULL,
    updated_at TIMESTAMPTZ DEFAULT now()
) LOCALITY GLOBAL;

6.3 Survival Goals(生存目標)

-- リージョン障害に耐える設定
ALTER DATABASE mydb SURVIVE REGION FAILURE;

-- ゾーン障害に耐える設定(デフォルト)
ALTER DATABASE mydb SURVIVE ZONE FAILURE;
  • ZONE FAILURE: 単一のアベイラビリティゾーンの障害に耐える(最小 3 ノード)
  • REGION FAILURE: リージョン全体の障害に耐える(最小 3 リージョン、各リージョン 3 ノード以上推奨)

6.4 Super Region

特定のリージョングループ内にデータを閉じ込める機能。データ主権要件に対応する。

-- Super Region の作成
ALTER DATABASE mydb ADD SUPER REGION "eu"
  VALUES "eu-west1", "eu-central1";

-- テーブルを Super Region に制約
ALTER TABLE eu_customer_data SET LOCALITY REGIONAL BY ROW;
-- eu_customer_data の行は eu Super Region 内のリージョンのみに配置される

6.5 Follower Reads

Leaseholder 以外のレプリカから読み取りを行い、読み取りレイテンシを低減する機能。

-- Exact Staleness Follower Read(正確な古さ指定)
SELECT * FROM users
AS OF SYSTEM TIME follower_read_timestamp();

-- Bounded Staleness Follower Read(制限付き古さ指定)
SELECT * FROM users
AS OF SYSTEM TIME with_min_timestamp(now() - '5s');

-- セッション単位での設定
SET default_transaction_use_follower_reads = true;

-- クラスタ設定
SET CLUSTER SETTING kv.closed_timestamp.target_duration = '3s';
SET CLUSTER SETTING kv.closed_timestamp.side_transport_interval = '1s';

6.6 マルチリージョン構成のベストプラクティス

# 3 リージョンクラスタの起動例
# US-East リージョン(3 ノード)
cockroach start \
  --locality=region=us-east1,zone=us-east1-a \
  --store=path=/data/cockroach \
  --advertise-addr=us-east1-node1:26257 \
  --join=us-east1-node1:26257,us-west1-node1:26257,eu-west1-node1:26257

# US-West リージョン(3 ノード)
cockroach start \
  --locality=region=us-west1,zone=us-west1-a \
  --store=path=/data/cockroach \
  --advertise-addr=us-west1-node1:26257 \
  --join=us-east1-node1:26257,us-west1-node1:26257,eu-west1-node1:26257

# EU-West リージョン(3 ノード)
cockroach start \
  --locality=region=eu-west1,zone=eu-west1-a \
  --store=path=/data/cockroach \
  --advertise-addr=eu-west1-node1:26257 \
  --join=us-east1-node1:26257,us-west1-node1:26257,eu-west1-node1:26257

レイテンシの考慮

パターン書き込みレイテンシ読み取りレイテンシユースケース
REGIONAL BY TABLE低(ホームリージョン)低(ホーム)/ 高(他)リージョン固定データ
REGIONAL BY ROW低(該当行のリージョン)低(ローカル行)ユーザーデータ
GLOBAL高(全リージョン合意必要)低(すべてのリージョン)マスタデータ

7. セキュリティ

7.1 認証

CockroachDB は複数の認証メカニズムをサポートする。

パスワード認証

-- ユーザー作成(パスワード付き)
CREATE USER app_user WITH PASSWORD 'secure_password_here';

-- パスワードの変更
ALTER USER app_user WITH PASSWORD 'new_secure_password';

-- パスワードハッシュアルゴリズムの設定
SET CLUSTER SETTING server.user_login.password_encryption = 'scram-sha-256';

証明書認証

# クライアント証明書の作成
cockroach cert create-client \
  app_user \
  --certs-dir=certs \
  --ca-key=my-safe-directory/ca.key

# 証明書を使用した接続
cockroach sql \
  --certs-dir=certs \
  --user=app_user \
  --host=node1.example.com:26257

GSSAPI / Kerberos 認証

# HBA(Host-Based Authentication)設定
# cockroach start --hba-conf-path=pg_hba.conf

# pg_hba.conf の例
host all all 0.0.0.0/0 gss include_realm=0 krb_realm=EXAMPLE.COM
host all all 0.0.0.0/0 cert
host all all 0.0.0.0/0 password

7.2 認可(RBAC)

CockroachDB は Role-Based Access Control(RBAC)を提供する。

-- ロールの作成
CREATE ROLE readonly_role;
CREATE ROLE readwrite_role;
CREATE ROLE admin_role;

-- 権限の付与
GRANT SELECT ON DATABASE mydb TO readonly_role;
GRANT SELECT, INSERT, UPDATE, DELETE ON DATABASE mydb TO readwrite_role;
GRANT ALL ON DATABASE mydb TO admin_role;

-- テーブルレベルの権限
GRANT SELECT ON TABLE mydb.public.users TO readonly_role;
GRANT SELECT, INSERT, UPDATE ON TABLE mydb.public.users TO readwrite_role;

-- スキーマレベルの権限
GRANT USAGE ON SCHEMA mydb.public TO readonly_role;
GRANT CREATE ON SCHEMA mydb.public TO readwrite_role;

-- ロールの割り当て
GRANT readonly_role TO app_readonly_user;
GRANT readwrite_role TO app_readwrite_user;
GRANT admin_role TO dba_user;

-- ロール階層
GRANT readonly_role TO readwrite_role;  -- readwrite は readonly の権限も持つ

-- 権限の確認
SHOW GRANTS ON DATABASE mydb;
SHOW GRANTS ON TABLE mydb.public.users;
SHOW GRANTS FOR app_user;

7.3 暗号化

転送中の暗号化(TLS)

# TLS 設定は前述の証明書設定を参照
# 最小 TLS バージョンの設定
cockroach start \
  --certs-dir=certs \
  --tls-min-version=1.2 \
  # ... その他のオプション

保存時の暗号化(Encryption at Rest)

# Encryption at Rest の有効化
cockroach start \
  --store=path=/data/cockroach,attrs=ssd \
  --enterprise-encryption=path=/data/cockroach,key=/path/to/aes-256.key,old-key=plain \
  # ... その他のオプション

# 暗号化キーのローテーション
cockroach start \
  --enterprise-encryption=path=/data/cockroach,key=/path/to/new-key.key,old-key=/path/to/old-key.key \
  # ... その他のオプション

7.4 監査ログ

-- SQL 監査ログの有効化(テーブル単位)
ALTER TABLE sensitive_data EXPERIMENTAL_AUDIT SET READ WRITE;

-- 監査ログの確認
SELECT * FROM crdb_internal.audit_log
ORDER BY timestamp DESC
LIMIT 20;

-- クラスタ全体の SQL イベントログ
SET CLUSTER SETTING sql.log.all_statements.enabled = true;
SET CLUSTER SETTING sql.log.slow_query.latency_threshold = '100ms';

7.5 ネットワークセキュリティ

# 特定インターフェースでのリッスン
cockroach start \
  --listen-addr=10.0.1.1:26257 \        # 内部通信
  --sql-addr=10.0.1.1:26257 \           # SQL クライアント
  --http-addr=10.0.1.1:8080 \           # Admin UI
  --advertise-addr=node1.internal:26257   # クラスタ内での広告アドレス

8. バックアップ、リストア、CDC

8.1 バックアップ

CockroachDB は Enterprise 機能として包括的なバックアップ機能を提供する。

-- フルバックアップ(クラスタ全体)
BACKUP INTO 's3://my-bucket/backups?AUTH=implicit'
  AS OF SYSTEM TIME '-10s';

-- データベース単位のバックアップ
BACKUP DATABASE mydb INTO 's3://my-bucket/backups/mydb'
  WITH revision_history;

-- テーブル単位のバックアップ
BACKUP TABLE mydb.public.users, mydb.public.orders
  INTO 's3://my-bucket/backups/tables';

-- 増分バックアップ
BACKUP INTO LATEST IN 's3://my-bucket/backups'
  AS OF SYSTEM TIME '-10s';

-- スケジュールバックアップ
CREATE SCHEDULE daily_backup FOR BACKUP INTO 's3://my-bucket/backups'
  WITH revision_history
  RECURRING '@daily'
  WITH SCHEDULE OPTIONS first_run = 'now';

-- フル + 増分のスケジュール
CREATE SCHEDULE full_and_incremental FOR BACKUP INTO 's3://my-bucket/backups'
  WITH revision_history
  RECURRING '0 */4 * * *'       -- 増分: 4 時間ごと
  FULL BACKUP '@weekly'          -- フル: 毎週
  WITH SCHEDULE OPTIONS first_run = 'now';

バックアップ先のストレージ

-- Amazon S3
BACKUP INTO 's3://bucket-name/path?AUTH=specified&AWS_ACCESS_KEY_ID=xxx&AWS_SECRET_ACCESS_KEY=yyy';

-- Google Cloud Storage
BACKUP INTO 'gs://bucket-name/path?AUTH=specified&CREDENTIALS=base64_encoded_json';

-- Azure Blob Storage
BACKUP INTO 'azure-blob://container-name/path?AZURE_ACCOUNT_NAME=xxx&AZURE_ACCOUNT_KEY=yyy';

-- NFS / ローカルファイルシステム
BACKUP INTO 'nodelocal://1/backups/';

-- HTTP エンドポイント
BACKUP INTO 'http://backup-server:8080/backups/';

8.2 リストア

-- クラスタ全体のリストア(空のクラスタに対して実行)
RESTORE FROM LATEST IN 's3://my-bucket/backups';

-- データベースのリストア
RESTORE DATABASE mydb FROM LATEST IN 's3://my-bucket/backups/mydb';

-- テーブルのリストア
RESTORE TABLE mydb.public.users FROM LATEST IN 's3://my-bucket/backups/tables';

-- ポイントインタイムリストア
RESTORE DATABASE mydb FROM LATEST IN 's3://my-bucket/backups'
  AS OF SYSTEM TIME '2024-01-15 10:30:00';

-- 別名でのリストア
RESTORE TABLE mydb.public.users FROM LATEST IN 's3://my-bucket/backups/tables'
  WITH into_db = 'mydb_restored';

8.3 Change Data Capture(CDC)

CDC は、テーブルの変更をリアルタイムでストリーミングする機能である。

-- Kafka への CDC フィード
CREATE CHANGEFEED FOR TABLE users, orders
  INTO 'kafka://kafka-broker:9092?topic_prefix=crdb_'
  WITH updated, resolved = '10s',
       format = 'json',
       diff,
       schema_change_policy = 'backfill';

-- Webhook への CDC フィード
CREATE CHANGEFEED FOR TABLE users
  INTO 'webhook-https://my-webhook-endpoint.com/events?insecure_tls_skip_verify=true'
  WITH updated, resolved = '30s',
       format = 'json';

-- Cloud Storage への CDC フィード
CREATE CHANGEFEED FOR TABLE users
  INTO 's3://my-bucket/cdc?AUTH=implicit'
  WITH updated, resolved = '1m',
       format = 'csv';

-- CDC ジョブの確認
SELECT job_id, description, status, created, started, finished
FROM [SHOW CHANGEFEED JOBS];

-- CDC ジョブの一時停止・再開
PAUSE JOB <job_id>;
RESUME JOB <job_id>;

CDC メッセージの形式(JSON)

{
  "key": ["uuid-123"],
  "value": {
    "after": {
      "id": "uuid-123",
      "username": "alice",
      "email": "alice@example.com",
      "created_at": "2024-01-15T10:30:00Z"
    },
    "before": null,
    "updated": "1705312200000000000.0000000000"
  },
  "topic": "crdb_users",
  "timestamp": "2024-01-15T10:30:00Z"
}

9. パフォーマンスチューニング

9.1 インデックス設計

-- セカンダリインデックス
CREATE INDEX idx_users_email ON users (email);

-- 複合インデックス
CREATE INDEX idx_orders_status_date ON orders (status, created_at DESC);

-- カバリングインデックス(STORING 句)
CREATE INDEX idx_orders_customer ON orders (customer_id)
  STORING (status, amount, created_at);

-- 部分インデックス
CREATE INDEX idx_active_orders ON orders (customer_id, created_at DESC)
  WHERE status = 'active';

-- 式インデックス
CREATE INDEX idx_users_lower_email ON users (lower(email));

-- Inverted インデックス(JSONB 用)
CREATE INVERTED INDEX idx_users_profile ON users (profile);

-- 地理空間インデックス
CREATE INDEX idx_locations_geom ON locations USING GIST (geom);

-- Hash-Sharded インデックス(ホットスポット防止)
CREATE TABLE events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    ts TIMESTAMPTZ NOT NULL DEFAULT now(),
    data JSONB,
    INDEX idx_events_ts (ts) USING HASH
);

9.2 クエリの最適化

-- スロークエリの検出
SELECT query, calls, mean_latency, max_latency
FROM crdb_internal.node_statement_statistics
WHERE mean_latency > interval '100ms'
ORDER BY mean_latency DESC
LIMIT 20;

-- インデックスの使用状況
SELECT ti.descriptor_name AS table_name,
       ti.index_name,
       ti.total_reads,
       ti.last_read
FROM crdb_internal.index_usage_statistics AS ti
ORDER BY ti.total_reads DESC;

-- 未使用インデックスの検出
SELECT ti.descriptor_name AS table_name,
       ti.index_name,
       ti.created_at
FROM crdb_internal.index_usage_statistics AS ti
WHERE ti.total_reads = 0
  AND ti.index_name != 'primary'
ORDER BY ti.created_at;

-- クエリプランのヒント
SELECT * FROM users@idx_users_email
WHERE email = 'alice@example.com';

-- Join の方法を指定
SELECT /*+ MERGE_JOIN */ *
FROM users
JOIN orders ON users.id = orders.customer_id;

SELECT /*+ HASH_JOIN */ *
FROM users
JOIN orders ON users.id = orders.customer_id;

SELECT /*+ LOOKUP_JOIN */ *
FROM users
JOIN orders ON users.id = orders.customer_id;

9.3 ホットスポットの対策

-- UUID によるキー分散(推奨)
CREATE TABLE events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    -- ...
);

-- Hash-Sharded インデックス
CREATE TABLE time_series (
    ts TIMESTAMPTZ NOT NULL,
    metric_name STRING NOT NULL,
    value FLOAT NOT NULL,
    PRIMARY KEY (ts, metric_name) USING HASH WITH (bucket_count = 8)
);

-- 手動 Range 分割
ALTER TABLE large_table SPLIT AT VALUES ('partition_key_1'), ('partition_key_2');

-- テーブルの Range 情報確認
SELECT start_key, end_key, range_id, lease_holder, replicas
FROM [SHOW RANGES FROM TABLE large_table];

-- Range の分散確認
SELECT range_id, start_pretty, end_pretty, lease_holder,
       array_length(replicas, 1) AS num_replicas
FROM crdb_internal.ranges_no_leases
WHERE table_name = 'large_table'
ORDER BY start_pretty;

9.4 メモリとストレージの設定

# メモリ設定(起動時)
cockroach start \
  --cache=.25 \          # 利用可能メモリの 25% をキャッシュに割り当て
  --max-sql-memory=.25 \ # 利用可能メモリの 25% を SQL 実行に割り当て
  # ... その他のオプション

# 絶対値での指定
cockroach start \
  --cache=4GiB \
  --max-sql-memory=4GiB \
  # ... その他のオプション
-- セッション単位のメモリ制限
SET distsql_workmem = '128 MiB';

-- 一時ディスク使用量の制限
SET CLUSTER SETTING sql.distsql.temp_storage.workmem = '128 MiB';

-- ストレージのコンパクション設定
SET CLUSTER SETTING rocksdb.min_wal_sync_interval = '500us';

9.5 接続プーリング

-- 最大接続数の設定
SET CLUSTER SETTING server.max_connections_per_gateway = 5000;

-- アイドル接続のタイムアウト
SET CLUSTER SETTING server.user_login.timeout = '10s';

CockroachDB では外部の接続プーラー(PgBouncer など)の使用も推奨される。

# pgbouncer.ini の設定例
[databases]
mydb = host=localhost port=26257 dbname=mydb

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = session        # CockroachDB には session モードが推奨
max_client_conn = 1000
default_pool_size = 50
min_pool_size = 10
reserve_pool_size = 5

9.6 Admission Control

CockroachDB v22.1+ では、Admission Control によりワークロードの優先度制御が可能。

-- セッションの優先度設定
SET default_transaction_quality_of_service = 'background';  -- バックグラウンド処理
SET default_transaction_quality_of_service = 'regular';     -- 通常処理(デフォルト)
SET default_transaction_quality_of_service = 'critical';    -- 重要処理

-- トランザクション単位
BEGIN;
SET transaction_quality_of_service = 'critical';
SELECT * FROM orders WHERE id = 'uuid-123';
COMMIT;

-- Admission Control の有効化
SET CLUSTER SETTING admission.kv.enabled = true;
SET CLUSTER SETTING admission.sql_kv_response.enabled = true;
SET CLUSTER SETTING admission.sql_sql_response.enabled = true;

10. 監視と運用

10.1 Admin UI(DB Console)

CockroachDB には組み込みの Web ベースの管理 UI が含まれている。デフォルトではポート 8080 でアクセス可能。

http://localhost:8080

DB Console で確認できる主な情報:

  • Cluster Overview: ノード数、Range 数、レプリケーション状態
  • Metrics: CPU、メモリ、ディスク I/O、ネットワーク、SQL レイテンシ
  • SQL Activity: アクティブなクエリ、トランザクション、セッション
  • Hot Ranges: アクセスが集中している Range
  • Jobs: バックアップ、スキーマ変更、CDC ジョブの状態
  • Databases: スキーマ情報、テーブルサイズ、インデックス
  • Network: ノード間のレイテンシマップ

10.2 Prometheus / Grafana 連携

CockroachDB は Prometheus 形式のメトリクスエンドポイントを公開している。

# prometheus.yml の設定例
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'cockroachdb'
    metrics_path: '/_status/vars'
    scheme: 'https'
    tls_config:
      ca_file: '/path/to/ca.crt'
      cert_file: '/path/to/client.root.crt'
      key_file: '/path/to/client.root.key'
    static_configs:
      - targets:
        - 'node1.example.com:8080'
        - 'node2.example.com:8080'
        - 'node3.example.com:8080'

重要なメトリクス

メトリクス説明警告閾値の目安
sql_query_countSQL クエリの総数-
sql_service_latency_p99SQL レイテンシの p99> 500ms
liveness_heartbeatfailuresハートビート失敗数> 0
ranges_unavailable利用不可の Range 数> 0
ranges_underreplicatedレプリカ不足の Range 数> 0
capacity_used_percentディスク使用率> 80%
sys_cpu_combined_percentCPU 使用率> 80%
sql_mem_root_currentSQL メモリ使用量> 80% of max
rocksdb_read_amplification読み取り増幅率> 20
admission_wait_durations_p99Admission Control 待機時間> 100ms

10.3 ログ設定

# logging.yaml の設定例
file-defaults:
  max-file-size: 10MiB
  max-group-size: 100MiB
  buffered-writes: true
  
sinks:
  file-groups:
    default:
      channels: ALL
      filter: INFO
    sql-audit:
      channels: [SENSITIVE_ACCESS]
      filter: INFO
      auditable: true
    security:
      channels: [USER_ADMIN, PRIVILEGES]
      filter: INFO
    health:
      channels: [HEALTH]
      filter: INFO
  
  fluent-servers:
    elk:
      channels: ALL
      address: elk-server:24224
      net: tcp
      filter: WARNING
# ログ設定を使用した起動
cockroach start \
  --log-config-file=logging.yaml \
  # ... その他のオプション

10.4 ヘルスチェック

# ノードのヘルスチェック
cockroach node status --certs-dir=certs --host=localhost:26257

# 特定ノードの詳細情報
cockroach node status 1 --certs-dir=certs --host=localhost:26257

# ヘルスチェック API
curl -k https://localhost:8080/health
curl -k https://localhost:8080/health?ready=1  # readiness check
-- ノードのステータス確認
SELECT node_id, address, is_live, is_available,
       gossiped_replicas, locality
FROM crdb_internal.gossip_nodes;

-- Range の健全性確認
SELECT range_id, start_pretty, end_pretty,
       array_length(replicas, 1) AS num_replicas,
       lease_holder
FROM crdb_internal.ranges
WHERE array_length(replicas, 1) < 3;

10.5 ノードの追加と廃止

# 新しいノードの追加(既存クラスタに参加)
cockroach start \
  --certs-dir=certs \
  --store=path=/data/cockroach \
  --listen-addr=new-node:26257 \
  --join=node1:26257,node2:26257,node3:26257

# ノードの廃止(Decommission)
cockroach node decommission 4 --certs-dir=certs --host=localhost:26257

# 廃止状態の確認
cockroach node decommission --status --certs-dir=certs --host=localhost:26257

# ノードのドレイン(graceful shutdown)
cockroach node drain 4 --certs-dir=certs --host=localhost:26257
-- クラスタ内のジョブ確認
SELECT job_id, job_type, description, status, 
       fraction_completed, created, finished
FROM crdb_internal.jobs
WHERE status = 'running'
ORDER BY created DESC;

11. スキーマ変更とマイグレーション

11.1 オンラインスキーマ変更

CockroachDB はオンラインスキーマ変更をサポートしており、DDL 操作中もテーブルへの読み書きが可能である。

-- カラムの追加(オンライン)
ALTER TABLE users ADD COLUMN phone STRING;

-- カラムの追加(デフォルト値付き)
ALTER TABLE users ADD COLUMN verified BOOL DEFAULT false;

-- カラムの削除
ALTER TABLE users DROP COLUMN phone;

-- カラム名の変更
ALTER TABLE users RENAME COLUMN verified TO is_verified;

-- インデックスの追加(オンライン、バックグラウンドで構築)
CREATE INDEX CONCURRENTLY idx_users_created ON users (created_at DESC);

-- テーブル名の変更
ALTER TABLE users RENAME TO app_users;

-- カラムの型変更(制限あり)
ALTER TABLE users ALTER COLUMN age TYPE BIGINT;

スキーマ変更ジョブの確認

-- 実行中のスキーマ変更ジョブ
SELECT job_id, description, status, fraction_completed
FROM [SHOW JOBS]
WHERE job_type = 'SCHEMA CHANGE'
  AND status = 'running';

-- スキーマ変更の一時停止・再開
PAUSE JOB <job_id>;
RESUME JOB <job_id>;
CANCEL JOB <job_id>;

11.2 宣言的スキーマ変更(v22.2+)

CockroachDB v22.2 以降では、新しい宣言的スキーマ変更エンジンが導入された。

-- 宣言的スキーマ変更の有効化
SET CLUSTER SETTING sql.defaults.use_declarative_schema_changer = 'on';

-- 複数の DDL を 1 つのトランザクションで実行可能
BEGIN;
  ALTER TABLE users ADD COLUMN bio STRING;
  ALTER TABLE users ADD COLUMN avatar_url STRING;
  CREATE INDEX idx_users_bio ON users (bio);
COMMIT;

11.3 マイグレーションツール

CockroachDB は以下のマイグレーションツールと互換性がある。

  • Flyway: SQL ベースのマイグレーション
  • Liquibase: XML/YAML/JSON ベースのマイグレーション
  • golang-migrate: Go 言語のマイグレーションライブラリ
  • Alembic: Python(SQLAlchemy)のマイグレーションツール
# Flyway の設定例
# flyway.conf
flyway.url=jdbc:postgresql://localhost:26257/mydb?sslmode=disable
flyway.user=root
flyway.password=
flyway.locations=filesystem:./migrations

# マイグレーション実行
flyway migrate

12. Kubernetes でのデプロイ

12.1 CockroachDB Operator

CockroachDB は Kubernetes 上でのデプロイに公式の Operator を提供している。

# CockroachDB Operator のインストール
# kubectl apply -f https://raw.githubusercontent.com/cockroachdb/cockroach-operator/master/install/crds.yaml
# kubectl apply -f https://raw.githubusercontent.com/cockroachdb/cockroach-operator/master/install/operator.yaml

# CockroachDB クラスタの定義(CRD)
apiVersion: crdb.cockroachlabs.com/v1alpha1
kind: CrdbCluster
metadata:
  name: cockroachdb
  namespace: cockroachdb
spec:
  dataStore:
    pvc:
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: "100Gi"
        storageClassName: ssd
  resources:
    requests:
      cpu: "4"
      memory: "16Gi"
    limits:
      cpu: "4"
      memory: "16Gi"
  tlsEnabled: true
  image:
    name: cockroachdb/cockroach:v24.1.0
  nodes: 3
  additionalLabels:
    app.kubernetes.io/name: cockroachdb
  additionalAnnotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
    prometheus.io/path: "/_status/vars"

12.2 Helm Chart でのデプロイ

# Helm リポジトリの追加
helm repo add cockroachdb https://charts.cockroachdb.com/
helm repo update

# values.yaml
cat <<EOF > values.yaml
statefulset:
  replicas: 3
  resources:
    requests:
      cpu: "4"
      memory: "16Gi"
    limits:
      cpu: "4"
      memory: "16Gi"

conf:
  cache: "4GiB"
  max-sql-memory: "4GiB"
  locality: "region=us-east1,zone=us-east1-a"
  join:
    - cockroachdb-0.cockroachdb.default.svc.cluster.local:26257
    - cockroachdb-1.cockroachdb.default.svc.cluster.local:26257
    - cockroachdb-2.cockroachdb.default.svc.cluster.local:26257

storage:
  persistentVolume:
    size: 100Gi
    storageClass: ssd

tls:
  enabled: true
  certs:
    provided: true

service:
  ports:
    grpc:
      external:
        port: 26257
    http:
      port: 8080
EOF

# デプロイ
helm install cockroachdb cockroachdb/cockroachdb -f values.yaml

12.3 StatefulSet(手動デプロイ)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cockroachdb
spec:
  serviceName: cockroachdb
  replicas: 3
  selector:
    matchLabels:
      app: cockroachdb
  template:
    metadata:
      labels:
        app: cockroachdb
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - cockroachdb
              topologyKey: kubernetes.io/hostname
      containers:
        - name: cockroachdb
          image: cockroachdb/cockroach:v24.1.0
          ports:
            - containerPort: 26257
              name: grpc
            - containerPort: 8080
              name: http
          command:
            - /cockroach/cockroach
            - start
            - --certs-dir=/cockroach/cockroach-certs
            - --advertise-addr=$(POD_NAME).cockroachdb.$(NAMESPACE).svc.cluster.local
            - --join=cockroachdb-0.cockroachdb.$(NAMESPACE).svc.cluster.local:26257,cockroachdb-1.cockroachdb.$(NAMESPACE).svc.cluster.local:26257,cockroachdb-2.cockroachdb.$(NAMESPACE).svc.cluster.local:26257
            - --cache=.25
            - --max-sql-memory=.25
            - --locality=region=us-east1,zone=us-east1-a
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          volumeMounts:
            - name: datadir
              mountPath: /cockroach/cockroach-data
            - name: certs
              mountPath: /cockroach/cockroach-certs
          resources:
            requests:
              cpu: "4"
              memory: "16Gi"
            limits:
              cpu: "4"
              memory: "16Gi"
          readinessProbe:
            httpGet:
              path: /health?ready=1
              port: http
              scheme: HTTPS
            initialDelaySeconds: 10
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: http
              scheme: HTTPS
            initialDelaySeconds: 30
            periodSeconds: 5
      volumes:
        - name: certs
          secret:
            secretName: cockroachdb-certs
  volumeClaimTemplates:
    - metadata:
        name: datadir
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: ssd
        resources:
          requests:
            storage: 100Gi
---
apiVersion: v1
kind: Service
metadata:
  name: cockroachdb
spec:
  clusterIP: None
  selector:
    app: cockroachdb
  ports:
    - port: 26257
      targetPort: grpc
      name: grpc
    - port: 8080
      targetPort: http
      name: http
---
apiVersion: v1
kind: Service
metadata:
  name: cockroachdb-public
spec:
  type: ClusterIP
  selector:
    app: cockroachdb
  ports:
    - port: 26257
      targetPort: grpc
      name: grpc
    - port: 8080
      targetPort: http
      name: http

12.4 Pod Disruption Budget

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: cockroachdb-pdb
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: cockroachdb

13. 高度な機能

13.1 Changefeeds の高度な設定

-- CDC フィルタリング(v22.2+)
CREATE CHANGEFEED FOR TABLE orders
  INTO 'kafka://broker:9092?topic_prefix=filtered_'
  WITH updated,
       format = 'json',
       where = 'status = ''completed'' AND amount > 1000';

-- Avro フォーマットでの出力
CREATE CHANGEFEED FOR TABLE users
  INTO 'kafka://broker:9092?topic_prefix=avro_'
  WITH updated,
       format = 'avro',
       confluent_schema_registry = 'http://schema-registry:8081';

-- CDC のパフォーマンス設定
SET CLUSTER SETTING changefeed.memory.per_changefeed_limit = '512 MiB';
SET CLUSTER SETTING changefeed.backfill.concurrent_scan_requests = 3;

13.2 ユーザー定義関数(UDF)

-- ユーザー定義関数の作成
CREATE FUNCTION calculate_tax(price DECIMAL, tax_rate DECIMAL)
RETURNS DECIMAL
LANGUAGE SQL
AS $$
  SELECT price * tax_rate;
$$;

-- UDF の使用
SELECT id, name, price, calculate_tax(price, 0.08) AS tax
FROM products;

-- UDF の一覧
SHOW FUNCTIONS;

-- UDF の削除
DROP FUNCTION calculate_tax;

13.3 Scheduled Jobs

-- スケジュールの作成(バックアップ以外)
-- 統計情報の定期更新
CREATE SCHEDULE stats_refresh FOR SQL
  'CREATE STATISTICS auto_stats FROM users'
  RECURRING '0 */6 * * *'  -- 6 時間ごと
  WITH SCHEDULE OPTIONS first_run = 'now';

-- スケジュールの確認
SHOW SCHEDULES;

-- スケジュールの一時停止・再開
PAUSE SCHEDULE <schedule_id>;
RESUME SCHEDULE <schedule_id>;
DROP SCHEDULE <schedule_id>;

13.4 テンポラリテーブルとマテリアライズドビュー

-- テンポラリテーブル
CREATE TEMPORARY TABLE temp_results (
    id INT PRIMARY KEY,
    result STRING
);

-- マテリアライズドビュー(v23.1+)
-- ※ CockroachDB では通常のビューが推奨されるが、
-- マテリアライズドビューも限定的にサポート
CREATE MATERIALIZED VIEW sales_summary AS
SELECT region,
       DATE_TRUNC('month', created_at) AS month,
       COUNT(*) AS order_count,
       SUM(amount) AS total_amount
FROM orders
GROUP BY region, DATE_TRUNC('month', created_at);

-- ビューのリフレッシュ
REFRESH MATERIALIZED VIEW sales_summary;

13.5 地理空間データ

-- 地理空間テーブルの作成
CREATE TABLE locations (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name STRING NOT NULL,
    geom GEOMETRY(Point, 4326) NOT NULL,
    INDEX idx_geom (geom) USING GIST
);

-- データの挿入
INSERT INTO locations (name, geom) VALUES
    ('Tokyo Tower', ST_GeomFromText('POINT(139.7454 35.6586)', 4326)),
    ('Eiffel Tower', ST_GeomFromText('POINT(2.2945 48.8584)', 4326)),
    ('Statue of Liberty', ST_GeomFromText('POINT(-74.0445 40.6892)', 4326));

-- 近傍検索
SELECT name, ST_Distance(
    geom::geography,
    ST_GeomFromText('POINT(139.7 35.7)', 4326)::geography
) AS distance_meters
FROM locations
ORDER BY geom <-> ST_GeomFromText('POINT(139.7 35.7)', 4326)
LIMIT 5;

-- 範囲検索
SELECT name FROM locations
WHERE ST_DWithin(
    geom::geography,
    ST_GeomFromText('POINT(139.7 35.7)', 4326)::geography,
    10000  -- 10km 以内
);

13.6 フルテキスト検索(Trigram インデックス)

-- Trigram インデックスの作成
CREATE INDEX idx_users_name_trgm ON users
  USING GIN (username gin_trgm_ops);

-- あいまい検索
SELECT * FROM users
WHERE username % 'alice';  -- trigram 類似度

-- LIKE / ILIKE の高速化
SELECT * FROM users
WHERE username ILIKE '%ali%';

14. 他のデータベースとの比較

14.1 CockroachDB vs PostgreSQL

観点CockroachDBPostgreSQL
アーキテクチャ分散型、シェアードナッシング単一ノード(レプリケーション対応)
スケーリング水平(ノード追加)垂直(リードレプリカで読み取りスケール)
分離レベルSerializable(デフォルト)Read Committed(デフォルト)
HA組み込み(Raft)外部ツール(Patroni, repmgr)
地理的分散ネイティブサポート手動構築が必要
互換性PostgreSQL ワイヤプロトコル-
拡張性限定的非常に高い(PostGIS, pg_vector 等)
パフォーマンス(単一ノード)やや劣る優れている

14.2 CockroachDB vs Google Cloud Spanner

観点CockroachDBGoogle Cloud Spanner
デプロイセルフホスト / マネージドマネージド(GCP のみ)
SQL 互換性PostgreSQL独自 SQL(PostgreSQL インターフェース対応)
クロックHLC(ソフトウェア)TrueTime(ハードウェア原子時計)
クロックスキュー~500ms(NTP 依存)~7ms(原子時計)
コスト予測可能使用量ベース(高額になりうる)
ベンダーロックなしGCP
オープンソースBSL(条件付き)非公開

14.3 CockroachDB vs TiDB

観点CockroachDBTiDB
SQL 互換性PostgreSQLMySQL
分離レベルSerializableSnapshot Isolation(SI)
ストレージPebble(組み込み)TiKV(分離されたストレージ層)
HTAPSQL + DistSQLTiFlash(列指向ストレージ)
ライセンスBSLApache 2.0
起源Google SpannerGoogle Spanner + F1

14.4 CockroachDB vs YugabyteDB

観点CockroachDBYugabyteDB
SQL 互換性PostgreSQLPostgreSQL + Cassandra CQL
ストレージPebble(LSM)DocDB(RocksDB ベース)
分離レベルSerializableSnapshot + Serializable
地理的分散ネイティブネイティブ
ライセンスBSLApache 2.0(Core)
APISQL のみSQL + CQL

15. トラブルシューティング

15.1 一般的な問題と対処法

ノードがクラスタに参加できない

# ジョインアドレスの確認
cockroach node status --certs-dir=certs --host=existing-node:26257

# ネットワーク疎通確認
nc -zv node1:26257

# クロックスキューの確認(500ms 以上のずれがあると参加拒否される)
cockroach debug time-offset --certs-dir=certs --host=localhost:26257

Range が利用不可(Unavailable)

-- Unavailable Range の特定
SELECT range_id, start_pretty, end_pretty, replicas, lease_holder
FROM crdb_internal.ranges
WHERE array_length(replicas, 1) < 3;

-- Range の詳細情報
SHOW RANGE FROM TABLE mydb.users FOR ROW ('uuid-123');

スロークエリの調査

-- アクティブクエリの確認
SELECT query_id, node_id, user_name, 
       start::STRING AS started,
       query
FROM [SHOW CLUSTER STATEMENTS]
WHERE application_name != '$ internal'
ORDER BY start;

-- クエリのキャンセル
CANCEL QUERY '<query_id>';

-- ステートメント統計のリセット
SELECT crdb_internal.reset_sql_stats();

-- 実行計画のキャッシュ確認
SELECT plan_gist, metadata->>'query' AS query,
       statistics->'statistics'->'cnt' AS exec_count,
       statistics->'statistics'->'runLat'->'mean' AS mean_latency
FROM crdb_internal.statement_statistics
ORDER BY (statistics->'statistics'->'runLat'->'mean')::FLOAT DESC
LIMIT 10;

ディスク容量不足

-- テーブルサイズの確認
SELECT table_name, 
       pg_size_pretty(range_size_mb * 1024 * 1024) AS total_size
FROM (
    SELECT table_name,
           SUM((crdb_internal.range_stats(start_key)->'key_bytes')::INT +
               (crdb_internal.range_stats(start_key)->'val_bytes')::INT) / (1024*1024) AS range_size_mb
    FROM crdb_internal.ranges
    WHERE database_name = 'mydb'
    GROUP BY table_name
)
ORDER BY range_size_mb DESC;

-- GC の TTL を短くして古いデータを削除
ALTER DATABASE mydb CONFIGURE ZONE USING gc.ttlseconds = 3600;

-- MVCC ガベージコレクションの強制実行
-- (通常は自動で行われるが、緊急時に手動実行)

ロック競合の調査

-- アクティブなロックの確認
SELECT * FROM crdb_internal.cluster_locks
WHERE granted = false
ORDER BY wait_start;

-- ブロックしているトランザクションの特定
SELECT blocking_txn_id, waiting_txn_id, 
       lock_key_pretty, lock_strength
FROM crdb_internal.cluster_locks
WHERE granted = false;

-- デッドロック発生時の確認
SELECT * FROM crdb_internal.transaction_contention_events
ORDER BY collection_ts DESC
LIMIT 20;

15.2 デバッグツール

# デバッグ ZIP の生成(サポート問い合わせ用)
cockroach debug zip debug.zip --certs-dir=certs --host=localhost:26257

# Raft のデバッグ
cockroach debug range <range_id> --certs-dir=certs --host=localhost:26257

# ストアの検査
cockroach debug check-store --store=path=/data/cockroach

# クラスタの健全性検査
cockroach debug doctor examine --certs-dir=certs --host=localhost:26257

16. 運用上のベストプラクティス

16.1 クラスタサイジング

ワークロードCPUメモリストレージノード数
開発・テスト2 vCPU8 GiB50 GiB SSD3
小規模本番4 vCPU16 GiB200 GiB SSD3
中規模本番8 vCPU32 GiB500 GiB SSD5-9
大規模本番16+ vCPU64+ GiB1+ TiB NVMe9+

16.2 推奨設定チェックリスト

# OS レベルの最適化
# 1. ファイルディスクリプタの上限設定
ulimit -n 65535

# 2. スワップの無効化(推奨)
sudo swapoff -a

# 3. NTP の設定確認
chronyc tracking

# 4. ディスク I/O スケジューラ(SSD の場合)
echo noop | sudo tee /sys/block/sda/queue/scheduler
-- クラスタレベルの推奨設定
SET CLUSTER SETTING server.time_until_store_dead = '5m0s';
SET CLUSTER SETTING kv.snapshot_rebalance.max_rate = '64 MiB';
SET CLUSTER SETTING kv.snapshot_recovery.max_rate = '64 MiB';
SET CLUSTER SETTING sql.stats.automatic_collection.enabled = true;
SET CLUSTER SETTING admission.kv.enabled = true;
SET CLUSTER SETTING admission.sql_kv_response.enabled = true;
SET CLUSTER SETTING admission.sql_sql_response.enabled = true;

-- 監視関連の推奨設定
SET CLUSTER SETTING sql.log.slow_query.latency_threshold = '100ms';
SET CLUSTER SETTING sql.log.slow_query.internal_queries.enabled = true;

16.3 バージョンアップグレード

# ローリングアップグレードの手順
# 1. リリースノートを確認し、互換性を確認

# 2. バックアップの取得
cockroach sql --execute="BACKUP INTO 's3://bucket/pre-upgrade-backup'"

# 3. 1 ノードずつアップグレード
# ノードを停止 → バイナリを置換 → ノードを起動
# 各ノードの起動後、クラスタの健全性を確認してから次のノードへ

# 4. アップグレードの確定(全ノード完了後)
cockroach sql --execute="SET CLUSTER SETTING version = crdb_internal.node_executable_version()"

# 注意: クラスタバージョンの確定後はダウングレードできない

16.4 災害復旧(DR)計画

-- プライマリ/スタンバイ構成(物理レプリケーション)
-- v23.2+ でサポート
-- プライマリクラスタ
ALTER VIRTUAL CLUSTER main START REPLICATION OF main
  ON 'postgresql://root@standby-cluster:26257?options=-ccluster%3Dsystem&sslmode=verify-full';

-- RPO/RTO の目安
-- マルチリージョン (SURVIVE REGION FAILURE): RPO=0, RTO=数秒
-- 増分バックアップ (4時間間隔): RPO=最大4時間, RTO=バックアップサイズ依存
-- 物理レプリケーション: RPO=数秒, RTO=数分

17. まとめ

17.1 CockroachDB の強み

  1. 真の水平スケーラビリティ: シャーディングの複雑さなしに、ノード追加だけでスケールアウト
  2. 強一貫性: Serializable 分離レベルによる完全な ACID 保証
  3. 地理的分散: マルチリージョンでの低レイテンシアクセスとデータ主権対応
  4. 高可用性: 自己修復、自動フェイルオーバー、ゼロダウンタイムスキーマ変更
  5. PostgreSQL 互換: 既存のエコシステムを活用可能
  6. Kubernetes ネイティブ: クラウドネイティブなデプロイと運用

17.2 考慮すべき点

  1. 単一ノード性能: 純粋な単一ノード性能では PostgreSQL に劣る場合がある
  2. 機能の成熟度: ストアドプロシージャ、トリガーなど一部の PostgreSQL 機能は限定的
  3. 運用の複雑さ: 分散システムの運用には特有の知識が必要
  4. ライセンス: BSL は一部の利用形態に制約がある
  5. クロックスキュー: NTP に依存するため、Google Spanner の TrueTime と比較して不確実性が大きい

17.3 適用判断のフローチャート

データの分散が必要?
├── YES → 強一貫性が必要?
│         ├── YES → PostgreSQL 互換が必要?
│         │         ├── YES → CockroachDB ✓
│         │         └── NO  → Spanner or CockroachDB
│         └── NO  → 結果整合性で十分 → Cassandra, DynamoDB
└── NO  → 単一ノードで十分
          ├── PostgreSQL の機能をフル活用 → PostgreSQL
          └── シンプルなスケールアップ → PostgreSQL / MySQL

17.4 バージョン履歴と主要な機能追加

バージョンリリース年主要な機能
v1.02017初の GA リリース
v2.02017JSON サポート、改善されたオプティマイザ
v19.12019CDC、コストベースオプティマイザ
v19.22019Follower Reads、Encryption at Rest
v20.12020Pebble ストレージエンジン(オプション)
v20.22020Spatial データ、Enum 型
v21.12021マルチリージョン抽象化
v21.22021サーバーレス(プレビュー)
v22.12022Admission Control、SQL 監査ログ
v22.22022宣言的スキーマ変更、CDC フィルタリング
v23.12023Read Committed 分離レベル、UDF
v23.22023物理レプリケーション
v24.12024パフォーマンス改善、ロック管理の強化

本ドキュメントは AI によって生成されたものであり、最新の公式ドキュメントと併せて参照することを推奨する。 公式ドキュメント: https://www.cockroachlabs.com/docs/