YugabyteDB:PostgreSQL互換のDistributed SQLをauto-shardingと自動フォールトトレランスで構築するインストールガイド

Database tutorial - IT technology blog
Database tutorial - IT technology blog

Quick Start:YugabyteDBを5分で起動する

PostgreSQLに慣れているなら好都合 — YugabyteDBはSQLの構文もツールもほぼそのまま使えます。最速で試す方法はDockerです:

docker pull yugabytedb/yugabyte

docker run -d --name yugabyte \
  -p 5433:5433 -p 7000:7000 -p 9000:9000 -p 9042:9042 \
  yugabytedb/yugabyte \
  bin/yugabyted start --daemon=false

30秒ほど待ってから接続を試みましょう:

psql -h 127.0.0.1 -p 5433 -U yugabyte -d yugabyte

ポートは5433(Postgresのデフォルト5432とは異なります)を使用しているため、同じマシンでPostgresが動いていてもポートの競合を避けられます。接続できたらテーブルを作成してみましょう:

CREATE TABLE employees (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  department VARCHAR(50),
  created_at TIMESTAMP DEFAULT NOW()
);

INSERT INTO employees (name, department) VALUES
  ('田中 太郎', 'Engineering'),
  ('佐藤 花子', 'DevOps'),
  ('鈴木 一郎', 'Backend');

SELECT * FROM employees;

完璧に動きます — これがもう分散型SQLデータベースで、コマンドはPostgresとほぼ同じです。WebダッシュボードはURL http://localhost:7000 で確認でき、クラスター情報・タブレット分散・ノードの健全性がすべて表示されます。

YugabyteDBとは何か、なぜ必要なのか

単体のPostgresはほとんどのアプリケーションで十分機能します — ただし、データが数千万レコードに増えたり、書き込みトラフィックが急増したり、複数リージョンへの同時デプロイが必要になると限界が見えてきます。そのときの選択肢はいくつかあります:アプリケーションコード内でシャーディングを手動実装する(複雑でバグが生まれやすい)、リードレプリカを使う(読み込みのみスケール可能で書き込みはスケールしない)、または分散データベースに移行する、といった方法です。

YugabyteDBはまさにその課題を解決するために生まれました。内部アーキテクチャは3層で構成されています:

  • YSQLレイヤー — PostgreSQLワイヤープロトコルと互換性があり、ほぼすべてのSQL構文とドライバーをそのまま使用できます
  • DocDB — RocksDBをベースに独自開発したストレージエンジンで、Raftコンセンサスによりノード間の一貫性を保証します
  • タブレットシステム — データを自動的にシャード(タブレットと呼ばれます)に分割し、各ノードに均等に分散します

最大の強みはauto-shardingです — シャードキーを定義したり、アプリにルーティングロジックを書く必要はありません。ノードの追加・削除時にYugabyteDBが自動でリバランスします。

純粋なPostgresとの主な違い

  • SERIALシーケンス:分散型の性質上、ギャップが生じます(ギャップは正常な動作でバグではありません)— 連続したIDが必要な場合はUUIDを使いましょう
  • 外部キー:正常に機能しますが、大きなテーブル間の重いJOINにはcolocationの宣言が必要です
  • エクステンション:pgcrypto、pg_stat_statementsなどの主要なものはサポートされていますが、すべてのエクステンションに対応しているわけではありません
  • デフォルトポート:YSQLは5433、YCQL(Cassandra互換API)は9042

マルチノードクラスターのセットアップ

DockerのSingleノードはdev/test用途向けです。フォールトトレランスを持つ本番クラスターをセットアップするには、最低3ノードが必要です。以下は3台のマシン(IP:192.168.1.1192.168.1.2192.168.1.3)を使った例です。

各マシンでダウンロードと展開を行います:

wget https://downloads.yugabyte.com/releases/2.21.0.0/yugabyte-2.21.0.0-b545-linux-x86_64.tar.gz
tar xvfz yugabyte-2.21.0.0-b545-linux-x86_64.tar.gz
cd yugabyte-2.21.0.0/

各ノードを順番に起動します:

# ノード1 — 最初に起動
./bin/yugabyted start \
  --advertise_address=192.168.1.1 \
  --cloud_location=aws.us-east-1.us-east-1a

# ノード2 — ノード1に参加
./bin/yugabyted start \
  --advertise_address=192.168.1.2 \
  --join=192.168.1.1 \
  --cloud_location=aws.us-east-1.us-east-1b

# ノード3 — ノード1に参加
./bin/yugabyted start \
  --advertise_address=192.168.1.3 \
  --join=192.168.1.1 \
  --cloud_location=aws.us-east-1.us-east-1c

ステータスを確認します:

./bin/yugabyted status

デフォルトのreplication factorは3なので、1ノードがダウンしてもクラスターは正常に動作し続けます — Raftコンセンサスが自動でリーダーを再選出するため、手動での介入は不要です。これは従来のPostgres Streaming Replicationとの大きな違いです。

マルチリージョン設定

複数リージョン(東京・シンガポール・ソウルなど)へのデプロイは、--cloud_locationパラメーターを実際のリージョンに合わせて指定するだけです:

# 東京ノード
./bin/yugabyted start \
  --advertise_address=10.0.1.1 \
  --join=10.0.1.1 \
  --cloud_location=aws.ap-northeast-1.ap-northeast-1a

# シンガポールノード
./bin/yugabyted start \
  --advertise_address=10.0.2.1 \
  --join=10.0.1.1 \
  --cloud_location=aws.ap-southeast-1.ap-southeast-1a

# ソウルノード
./bin/yugabyted start \
  --advertise_address=10.0.3.1 \
  --join=10.0.1.1 \
  --cloud_location=aws.ap-northeast-2.ap-northeast-2a

その後、tablespaceを使って特定リージョンにデータを固定することで、各地域のユーザーへのレイテンシーを削減できます:

CREATE TABLESPACE tokyo_ts WITH (
  replica_placement='{"num_replicas": 1, "placement_blocks": [
    {"cloud": "aws", "region": "ap-northeast-1", "zone": "ap-northeast-1a", "min_num_replicas": 1}
  ]}'
);

CREATE TABLE orders (
  id BIGSERIAL,
  user_id INT,
  region TEXT NOT NULL,
  amount DECIMAL(10,2),
  PRIMARY KEY (id, region)
) PARTITION BY LIST (region);

CREATE TABLE orders_tokyo PARTITION OF orders
  FOR VALUES IN ('tokyo')
  TABLESPACE tokyo_ts;

YugabyteDBを使う際の実践的なTips

1. 分散ワークロードではSERIALの代わりにUUIDを使う

CREATE EXTENSION IF NOT EXISTS pgcrypto;

CREATE TABLE sessions (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id INT,
  token TEXT,
  expires_at TIMESTAMP
);

UUIDはタブレット全体により均等に分散されるため、大量insertの際のホットスポットを避けられます。

2. 頻繁にJOINする小さなテーブルにはColocationを使う

-- Colocationあり — 小さなテーブルを同じタブレットに格納
CREATE DATABASE myapp WITH COLOCATION = true;

-- 大きなテーブルはcolocationを個別に無効化
CREATE TABLE large_events (...) WITH (COLOCATION = false);

3. CSV/JSONからデータをインポートする

CSVからデータベースにテストデータをインポートする際、自分はまずJSONに変換してからPythonスクリプトでインポートするようにしています。よく使うのはtoolcraft.app/ja/tools/data/csv-to-jsonのコンバーター — ブラウザ上で動くのでデータ漏洩の心配がなく、スクリプトを自分で書くより断然便利です。

JSONファイルができたら、psycopg2を使ったPythonスクリプトでインポートします(接続方法はPostgresとまったく同じです):

import psycopg2
import json

conn = psycopg2.connect(
    host="127.0.0.1",
    port=5433,          # YugabyteDBのYSQLポート
    database="yugabyte",
    user="yugabyte",
    password="yugabyte"
)

with open("data.json") as f:
    records = json.load(f)

cur = conn.cursor()
for record in records:
    cur.execute(
        "INSERT INTO employees (name, department) VALUES (%s, %s)",
        (record["name"], record["department"])
    )

conn.commit()
cur.close()
conn.close()
print(f"Imported {len(records)} records")

4. バックアップとリストア

# バックアップ — pg_dumpと同じ構文
./bin/ysql_dump -h 127.0.0.1 -p 5433 -U yugabyte yugabyte > backup.sql

# リストア
./bin/ysqlsh -h 127.0.0.1 -p 5433 -U yugabyte -d yugabyte -f backup.sql

5. REST APIでヘルスチェックを行う

# 全体的なヘルス確認
curl http://localhost:7000/api/v1/health-check

# 各ノードのタブレット分散状況
curl http://localhost:7000/api/v1/tablet-servers

YugabyteDBを使うべきタイミング

すべてのプロジェクトにdistributed SQLが必要なわけではありません。YugabyteDBが適しているのは以下のような場合です:

  • 書き込みの水平スケーリングが必要な場合 — 書き込みトラフィックが単一Postgresノードの処理能力を超えている
  • マルチリージョンのアクティブ-アクティブが必要な場合 — 複数の地理的リージョンのユーザーが低レイテンシーを必要としている
  • 深夜3時にフェイルオーバーを手動対応したくなく、自動フォールトトレランスが欲しい場合
  • SQLをそのまま維持したい場合 — NoSQLへのリファクタリングやORMの変更をしたくない

アプリがPostgresのSingleノードで問題なく動いているなら、急いで移行する必要はありません。分散システムにはそれ相応の複雑さが伴います — ノード間のネットワークレイテンシー、エッジケースでのレプリケーション遅延など。ただし、スケールが必要なラインに到達したとき、YugabyteDBはクエリの書き直しも新しいデータモデルの習得も不要なため、最も悩まずに済む選択肢です。

Share: