PostgreSQLのデータ量が数億行を超えたとき、単一サーバーでは追いつかなくなります。Citusは PostgreSQL をそのまま水平スケールさせる拡張機能で、テーブルを複数のシャードに分割して並列処理できるようになります。SQL の書き方はほぼ変わらず、普通の PostgreSQL として使い続けながら分散データベースの恩恵を受けられるのが特徴です。
この記事では Ubuntu 22.04 LTS 上で PostgreSQL 16 + Citus 14.1 を実際にインストールし、分散テーブルを作成してシャーディングが動いている様子を実測で確認しました。シングルサーバーの開発環境から始めて、本番の複数ノード構成に移行するときの基礎として役立ててください。
この記事のポイント
- Ubuntu 22.04 で
postgresql-16-citus-14.1をインストールしcitus_version()で Citus 14.1.0 を実測確認(PostgreSQL 16.14) shared_preload_libraries = 'citus'を postgresql.conf に追加し、再起動してからCREATE EXTENSION citus- シングルノード開発環境では
citus_set_node_property(..., 'shouldhaveshards', true)が必須。これを忘れるとシャードが 0 のまま無言で終わる create_distributed_table('orders', 'user_id')一行でシャードキーを指定できる。実行計画にCustom Scan (Citus Adaptive)と出れば分散クエリが動いている証拠- Citusリポジトリは PostgreSQL 15 / 16 / 17 に対応したパッケージを提供している
目次
- 前提環境と確認事項
- Citusリポジトリの追加
- PostgreSQL 16 + Citus 14.1 のインストール
- postgresql.conf の設定変更
- Citus拡張の有効化とバージョン確認
- シングルノードセットアップ(shouldhaveshards)
- 分散テーブルの作成とシャーディングデモ
- よくあるエラーと解決策
- まとめ
前提環境と確認事項
今回の検証環境は以下のとおりです。インストールと citus_version() の確認は Ubuntu 22.04 LTS(Docker ubuntu:22.04)で実施しました。シャーディングの SQL デモは citusdata/citus:14.0 の公式 Docker イメージを使って実測しています。

| 確認項目 | 値 |
|---|---|
| OS | Ubuntu 22.04 LTS (Jammy Jellyfish) |
| PostgreSQL | 16.14(postgresql.org リポジトリから) |
| Citus | 14.1.0(14.1.0.citus-1) |
| 確認方法 | Docker ubuntu:22.04 で全コマンドを実行して stdout を取得 |
注意
VPS や専用サーバーで作業する場合は sudo を先頭につけて実行してください。またCitusをインストールする前に PostgreSQL が動いていない状態から始めることをおすすめします。すでにPostgreSQLを使っているサーバーに追加する場合は、バージョンの整合性を必ず確認してください。
STEP 1: Citusリポジトリの追加
Citus は Ubuntu 標準のリポジトリには含まれていません。Citus Data(現 Microsoft)が管理する apt リポジトリを追加するところから始めます。
$ sudo apt-get install -y curl gnupg2 ca-certificates
$ curl -s https://install.citusdata.com/community/deb.sh | sudo bash
Adding repository for Citus on Ubuntu 22.04 (jammy)…
Adding deb https://repos.citusdata.com/community/ubuntu jammy main
Importing Citus GPG key…
Done.
install.citusdata.com/community/deb.sh は apt のリポジトリ設定と GPG 鍵を自動で追加するスクリプトです。Ubuntu のバージョンを自動検出して適切なリポジトリを設定します。
STEP 2: PostgreSQL 16 + Citus 14.1 のインストール
リポジトリを追加したら apt-get update で一覧を更新してからインストールします。インストール時にPostgreSQLが依存関係として自動的に入るため、事前に別途インストールしておく必要はありません。
$ sudo apt-get install -y postgresql-16-citus-14.1
Get:1 … postgresql-16 16.14-1.pgdg22.04+1 [18.2 MB]
Get:2 … postgresql-16-citus-14.1 14.1.0.citus-1
Setting up postgresql-16 (16.14-1.pgdg22.04+1) …
Creating new PostgreSQL cluster 16/main …
Setting up postgresql-16-citus-14.1 (14.1.0.citus-1) …

インストール後にパッケージが正しく入ったかを確認します。私の環境では以下のように表示されました。
ii postgresql-16 16.14-1.pgdg22.04+1
ii postgresql-16-citus-14.1 14.1.0.citus-1
ii postgresql-client-16 16.14-1.pgdg22.04+1
ii postgresql-client-common 291.pgdg22.04+1
ii postgresql-common 291.pgdg22.04+1

STEP 3: postgresql.conf の設定変更
Citus を有効化するには postgresql.conf に shared_preload_libraries = 'citus' を追加し、PostgreSQL を再起動する必要があります。 この設定を忘れると CREATE EXTENSION citus を実行したときにエラーになります。
/etc/postgresql/16/main/postgresql.conf
$ grep “shared_preload_libraries” /etc/postgresql/16/main/postgresql.conf
shared_preload_libraries = ‘citus’ # (change requires restart)
$ sudo systemctl restart postgresql
$ sudo systemctl status postgresql
● postgresql.service – PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled)
Active: active (running)
もし Nginx や他のミドルウェアと同居している場合、再起動で既存の接続が一瞬切れます。メンテナンス時間帯に作業するか、pg_reload_conf() でリロードできないか確認してください(ただし shared_preload_libraries の変更は再起動必須です)。
STEP 4: Citus拡張の有効化とバージョン確認
PostgreSQL を再起動したら、psql で接続して Citus 拡張を作成します。
psql (16.14 (Ubuntu 16.14-1.pgdg22.04+1))
Type “help” for help.
postgres=# CREATE EXTENSION citus;
CREATE EXTENSION
postgres=# SELECT citus_version();
citus_version
———————————————————————-
Citus 14.1.0 on x86_64-pc-linux-gnu, compiled by gcc 11.4.0, 64-bit
(1 row)
CREATE EXTENSION と表示されれば Citus の有効化は成功です。ここまで約5分で完了しました(Docker コンテナでの計測で、ネットワーク速度による)。

STEP 5: シングルノードセットアップ(shouldhaveshards の設定)
以降の SQL デモについて
STEP 5 以降のシャーディングデモは、公式 citusdata/citus:14.0 Docker イメージ(Citus 14.0.0)を使って実測しています。Ubuntu 22.04 に apt でインストールした Citus 14.1.0 でも同じ SQL と手順が動作します。
ここが詰まりやすいポイントです。Citus をインストールしただけでは分散テーブルのシャードが作られません。シングルサーバーで使うときは「このコーディネーターにもシャードを置いてよい」という設定を明示する必要があります。
postgres=# SELECT citus_set_coordinator_host(‘localhost’, 5432);
citus_set_coordinator_host
—————————-
(1 row)
— シングルノード: コーディネーター自身にシャードを配置できるよう設定
postgres=# SELECT citus_set_node_property(‘localhost’, 5432, ‘shouldhaveshards’, true);
citus_set_node_property
————————-
(1 row)
— 設定を確認
postgres=# SELECT nodeid, nodename, nodeport, isactive, shouldhaveshards
FROM pg_dist_node;
nodeid | nodename | nodeport | isactive | shouldhaveshards
——–+———–+———-+———-+—————–
1 | localhost | 5432 | t | t
(1 row)
なぜこの設定が必要なのか
Citusはデフォルトで「コーディネーターノードにはシャードを置かない」という設計になっています。本番の複数ノード構成では、コーディネーターはクエリの調停役に徹してワーカーノードにデータを分散させます。シングルノードで開発するときだけ、shouldhaveshards = true でコーディネーター自身をシャード配置先として許可する必要があります。
STEP 6: 分散テーブルの作成とシャーディングデモ
設定が整ったら、実際に分散テーブルを作ってシャーディングが動くことを確認します。ECサイトの注文テーブルを例に使います。
①テーブルを作成して分散テーブルに変換する
postgres=# CREATE TABLE orders (
order_id BIGSERIAL,
user_id BIGINT NOT NULL,
product_id INTEGER NOT NULL,
amount NUMERIC(10,2),
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE
— user_id をシャードキーとして 8 シャードに分散
postgres=# SELECT create_distributed_table(‘orders’, ‘user_id’, shard_count => 8);
create_distributed_table
————————–
(1 row)
create_distributed_table の第2引数がシャードキーです。ここに user_id を指定すると、同じユーザーの注文は必ず同じシャードに入ります。範囲クエリや集計クエリがユーザー単位なら、このキー選定が理想的です。
②シャードが作られたことを確認する
FROM pg_dist_shard s
JOIN pg_dist_shard_placement sp USING (shardid)
WHERE s.logicalrelid = ‘orders’::regclass
ORDER BY s.shardid;
shardid | nodename | nodeport | shardstate
———+———–+———-+————
102008 | localhost | 5432 | 1
102009 | localhost | 5432 | 1
102010 | localhost | 5432 | 1
102011 | localhost | 5432 | 1
102012 | localhost | 5432 | 1
102013 | localhost | 5432 | 1
102014 | localhost | 5432 | 1
102015 | localhost | 5432 | 1
(8 rows)

シャードID 102008〜102015 の8つが localhost:5432 に配置されました。shardstate = 1 は「有効(Active)」を意味します。本番環境で複数ワーカーノードがある場合は、各行の nodename/nodeport が異なるサーバーになります。
③データを挿入して分散クエリを確認する
postgres=# INSERT INTO orders (user_id, product_id, amount)
SELECT (random()*999+1)::bigint,
(random()*99+1)::int,
(random()*4999+1)::numeric(10,2)
FROM generate_series(1,10000);
INSERT 0 10000
— ユーザー別の購入合計(分散集計クエリ)
postgres=# SELECT user_id, SUM(amount) AS total_spent, COUNT(*) AS order_count
FROM orders GROUP BY user_id ORDER BY total_spent DESC LIMIT 5;
user_id | total_spent | order_count
———+————-+————-
231 | 65202.49 | 21
563 | 54495.58 | 20
545 | 53507.20 | 19
942 | 52775.15 | 17
86 | 52233.87 | 16
(5 rows)
④実行計画で分散クエリを確認する
EXPLAIN で確認すると、Citusが分散クエリとして処理していることが見えます。
SELECT user_id, SUM(amount) FROM orders
WHERE user_id BETWEEN 100 AND 200 GROUP BY user_id;
QUERY PLAN
—————————————————————————
Custom Scan (Citus Adaptive)
Task Count: 8
Tasks Shown: One of 8
-> Task
Node: host=localhost port=5432 dbname=postgres
-> GroupAggregate
Group Key: user_id
-> Sort
-> Seq Scan on orders_102008 orders
(11 rows)

Custom Scan (Citus Adaptive) と Task Count: 8 が出ていれば、Citus が 8 つのシャードに並列でクエリを投げています。スキャン対象が orders ではなく orders_102008(シャードテーブル)になっている点も確認ポイントです。

よくあるエラーと解決策
①ERROR: Citus extension needs to be loaded — shared_preload_libraries
DETAIL: Citus extension needs to be loaded via shared_preload_libraries.
shared_preload_libraries = 'citus' を postgresql.conf に追加してから sudo systemctl restart postgresql を実行していないケースです。設定を確認してから再起動してください。
②シャード数が 0 のまま(shouldhaveshards を忘れた)
count
——-
0
(1 row)
私が最初につまずいた問題です。create_distributed_table はエラーなく完了するのにシャードが 0 のままで、データは普通の単一テーブルとして動きます。citus_set_node_property('localhost', 5432, 'shouldhaveshards', true) を実行してから再度試してください。テーブルが作成済みの場合は一度 DROP TABLE orders してやり直す必要があります。
③ERROR: replication_factor (1) exceeds number of worker nodes (0)
HINT: Add more worker nodes or try again with a lower replication factor.
citus_set_coordinator_host を実行していない、または実行後に shouldhaveshards を設定していない状態です。STEP 5 の手順を最初からやり直してください。
まとめ
Ubuntu 22.04 に Citus 14.1 をインストールして、PostgreSQL を水平分散させるまでの手順を実測で確認しました。
- Citus リポジトリを追加し
postgresql-16-citus-14.1をapt installするだけで入る shared_preload_libraries = 'citus'→ 再起動 →CREATE EXTENSION citusが有効化の最短路- シングルノードでは
shouldhaveshards = trueが必須。忘れるとシャードが 0 のまま無言で終わる - 実行計画に
Custom Scan (Citus Adaptive)と出れば Citus の分散クエリが動いている - Ubuntu 22.04 で
postgresql-16-citus-14.1をインストールし、citus_version()で Citus 14.1.0(PostgreSQL 16.14)を実測確認した
本番でスケールアウトするときは、ワーカーノードを追加して citus_add_node('worker-host', 5432) で登録し、rebalance_table_shards('orders') でシャードを再分散できます。まずはシングルノードで DDL と基本的な SQL の動作を確認してから、段階的にノードを増やすのが現実的です。
VPS で Citus を使う場合、ノード間の通信レイテンシが性能に直結します。東京リージョンを選ぶと国内ユーザーへのレイテンシが小さく、ノード間通信も速くなります。
PostgreSQL の基本的なサーバー構築から始めたい場合は も参考にしてください。


コメント