Citus 分散式 PostgreSQL:水平擴展到多節點叢集 | PostgreSQL

2026/07/26
Citus 分散式 PostgreSQL:水平擴展到多節點叢集 | PostgreSQL

當單機 PostgreSQL 的容量與吞吐量已無法滿足業務成長,Citus 分散式擴展提供了一條不換資料庫、不離開 PG 生態的水平擴展之路。本文將從 Coordinator-Workers 架構到 Colocation 共置機制,從 Hash 分片策略到 Schema-based Sharding,完整解析如何將 PostgreSQL 擴展為多節點分散式叢集。

系列最終篇:為什麼需要分散式?

在前 49 篇文章中,我們從 PostgreSQL 基礎語法一路走到雲端託管與開發者工具。但有一個問題始終懸而未決——當資料量超過單機極限,該怎麼辦?

垂直擴展(Scale-Up)終有天花板:記憶體、CPU、磁碟 I/O 都受限於單一主機的物理規格。當你面對以下場景時,水平擴展(Scale-Out)成為必要選擇:

  • 資料量超過 2TB,單機存儲與備份壓力過大
  • 寫入吞吐量突破 單一 Primary 的瓶頸(讀取副本無法分攤寫入)
  • 多租戶 SaaS 需要將租戶資料分散在不同節點以實現隔離
  • 時序/事件資料持續增長,需要無限水平擴容

Citus 正是解決這類問題的 PostgreSQL 原生方案——它以 Extension 形式存在,不需要換資料庫引擎,所有 PostgreSQL 的 SQL 語法、函數、Extension 都能繼續使用。


Citus 是什麼?

Citus 是 PostgreSQL 的分散式擴展(Distributed Extension),透過水平分片(Sharding)機制將單一資料庫擴展為多節點叢集。最初由 Citus Data 公司開發,2019 年被微軟收購,現已完全開源。

核心定位:

項目說明
類型PostgreSQL Extension(CREATE EXTENSION citus
授權AGPL-3.0(完全開源)
雲端服務Azure Database for PostgreSQL – Flexible Server
最新版本Citus 13.x(2025,支援 PG 17)
適用場景多租戶 SaaS、大規模分析、時序資料

Coordinator-Workers 架構

Citus 採用**協調者-工作者(Coordinator-Workers)**架構,所有節點都是完整的 PostgreSQL 實例:

┌─────────────────────────────────────────────────────┐
│                 應用程式 / Client                      │
│          (連接 Coordinator,行為與普通 PG 相同)       │
└────────────────────────┬────────────────────────────┘
                         │  標準 PostgreSQL 連線
                         ▼
┌─────────────────────────────────────────────────────┐
│                  Coordinator 節點                     │
│  ┌───────────────────────────────────────────────┐  │
│  │  Query Planner(分散式查詢計畫器)               │  │
│  │  ├─ 解析 SQL → 判斷是否涉及分散表               │  │
│  │  ├─ 產生分散式查詢計畫                          │  │
│  │  ├─ 路由至對應 Shard 所在 Worker                │  │
│  │  └─ 合併各 Worker 的結果並回傳                  │  │
│  ├───────────────────────────────────────────────┤  │
│  │  Metadata(元資料)                             │  │
│  │  ├─ pg_dist_node:節點清單                      │  │
│  │  ├─ pg_dist_shard:Shard 與分片範圍              │  │
│  │  └─ pg_dist_placement:Shard 在哪個 Worker      │  │
│  └───────────────────────────────────────────────┘  │
└──────────┬──────────────┬──────────────┬────────────┘
           │              │              │
    ┌──────▼─────┐  ┌─────▼──────┐  ┌───▼──────────┐
    │  Worker 1  │  │  Worker 2  │  │   Worker N   │
    │ ┌────────┐ │  │ ┌────────┐ │  │ ┌──────────┐ │
    │ │Shard 1 │ │  │ │Shard 2 │ │  │ │Shard N-1 │ │
    │ │Shard 5 │ │  │ │Shard 6 │ │  │ │Shard N   │ │
    │ └────────┘ │  │ └────────┘ │  │ └──────────┘ │
    └────────────┘  └────────────┘  └──────────────┘

角色分工

Coordinator(協調者):

  • 接收所有應用程式的 SQL 連線
  • 解析查詢,判斷哪些 Shard 需要被訪問
  • 將查詢拆解並**平行下推(Push Down)**至對應 Worker
  • 合併各 Worker 回傳結果
  • 維護分散式元資料

Worker(工作者):

  • 儲存實際的 Shard 資料(每個 Shard 是一個普通的 PostgreSQL 表)
  • 執行 Coordinator 下推的子查詢
  • 可直接接受其他 Worker 的連線(Shard 間資料移動時)

重要限制

  • 應用程式只連接 Coordinator,不直接連接 Worker
  • Coordinator 本身不儲存分散表資料,只儲存元資料與參考表
  • 單點故障風險:Coordinator 不可用時整個叢集無法接受新查詢(需配合 HA 方案)

分散表(Distributed Table)

分散表是 Citus 的核心概念。普通表轉換為分散表後,資料依照**分片鍵(Distribution Column)**分散儲存在各 Worker 的 Shard 中:

-- 建立普通表
CREATE TABLE orders (
    order_id    BIGINT NOT NULL,
    customer_id BIGINT NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL,
    amount      NUMERIC(12,2),
    status      TEXT
);

-- 轉換為分散表,以 customer_id 為分片鍵
SELECT create_distributed_table('orders', 'customer_id');

-- Citus 自動建立 32 個 Shard(預設值),分布在所有 Worker 上
-- orders_102008, orders_102009, ... 每個都是 Worker 上的真實 PG 表

分片鍵的選擇原則

分片鍵的選擇是 Citus 架構設計中最重要的決策

原則說明範例
高基數(High Cardinality)避免資料傾斜customer_id 優於 status
查詢對齊大多數查詢應包含分片鍵WHERE 條件常帶 customer_id
JOIN 對齊需 JOIN 的表用相同分片鍵orders 與 order_items 共用 tenant_id
不可變性分片鍵值不可 UPDATECitus 不支援跨 Shard 的分片鍵更新

參考表(Reference Table)

參考表是完整複製到每個 Worker的小型資料集,適合維度資料或頻繁 JOIN 的查詢表:

-- 建立參考表
CREATE TABLE countries (
    country_code CHAR(2) PRIMARY KEY,
    country_name TEXT NOT NULL,
    region       TEXT
);

SELECT create_reference_table('countries');

-- 分散表與參考表的 JOIN 在各 Worker 本地完成(零跨節點通訊)
SELECT o.order_id, o.amount, c.country_name
FROM orders o
JOIN countries c ON o.country_code = c.country_code
WHERE o.customer_id = 12345;
-- 路由到單一 Worker,JOIN 在本地完成

分散表 vs 參考表

特性分散表參考表
資料規模百萬至億筆數千至數萬筆
儲存方式分片,各 Worker 部分資料全量複製,各 Worker 完整資料
JOIN 效率需分片鍵對齊可與任何表在本地 JOIN
寫入開銷僅寫入對應 Shard需同步寫入所有 Worker(2PC)
適用場景主要業務資料表國家/幣別/類別等查詢表

Shard 策略:Hash vs Append

Hash Distribution(預設,最常用)

SELECT create_distributed_table('orders', 'customer_id');

運作原理:

customer_id = 1001
     │
     ▼
hash(1001) = 394857293
     │
     ▼
394857293 mod 32 = 13   (Shard index)
     │
     ▼
Shard 13 → Worker 2

特點:

  • 資料均勻分散,避免熱點
  • 適合 OLTP 工作負載
  • 支援 =IN 條件的 Shard Pruning
  • 範圍查詢(BETWEEN>)需掃描所有 Shard

Append Distribution(追加分片)

SELECT create_distributed_table('events', 'created_at', 'append');

特點:

  • 每個 Shard 儲存特定範圍(如時間區間)
  • 適合 Append-Only 工作負載(日誌、事件流)
  • 現代架構中較少使用,多以 Hash 分片 + 時間分割取代

策略比較

特性HashAppend
資料分布均勻雜湊分散依範圍追加
適用場景OLTP、多租戶時序、批次 ETL
Shard 管理自動手動
UPDATE/DELETE支援不建議
範圍查詢需掃描所有 Shard可利用範圍裁剪

分散式查詢路由

Citus 的查詢路由分為兩種模式,效能差異巨大:

Router Query(路由查詢)— 最佳路徑

當查詢包含分片鍵的等值過濾時,Coordinator 精確定位到單一 Shard:

-- Router Query:定位到單一 Shard,效能等同單機 PG
SELECT * FROM orders WHERE customer_id = 12345;

INSERT INTO orders (order_id, customer_id, amount)
VALUES (9001, 12345, 99.99);

UPDATE orders SET status = 'shipped' WHERE customer_id = 12345;

執行計畫:

Custom Scan (Citus Router)
  Task Count: 1
  ->  Task
        Node: host=worker1 port=5432
        ->  Index Scan using orders_pkey on orders_102009
              Filter: (customer_id = 12345)

Real-Time Query(實時查詢)— 平行掃描

不包含分片鍵或需要跨 Shard 聚合時,平行下推到所有 Worker:

-- Real-Time Query:平行掃描所有 Shard
SELECT status, COUNT(*), SUM(amount)
FROM orders
GROUP BY status;

-- 沒有分片鍵過濾,需掃描所有 Shard
SELECT * FROM orders WHERE amount > 1000;

執行計畫:

Custom Scan (Citus Real-Time)
  Task Count: 32
  Tasks Shown: One of 32
  ->  Task
        Node: host=worker1 port=5432
        ->  HashAggregate
              ->  Seq Scan on orders_102008

跨 Shard JOIN 的挑戰

-- 問題:orders 和 shipments 分片鍵不同,需大量跨節點資料移動
SELECT o.order_id, s.tracking_number
FROM orders o          -- 以 customer_id 分片
JOIN shipments s ON o.order_id = s.order_id;  -- 以 order_id 分片

-- 解決方案:加上分片鍵條件 + Subquery Pushdown
SELECT o.order_id, s.tracking_number
FROM orders o
JOIN (SELECT order_id, tracking_number FROM shipments) s
    ON o.order_id = s.order_id
WHERE o.customer_id = 12345;  -- 加上分片鍵

Colocation(資料共置)

Colocation 是 Citus 效能最佳化的核心機制。當多張分散表使用相同分片鍵與分片數量時,Citus 保證相同鍵值的資料落在同一個 Worker:

-- 以 tenant_id 為分片鍵,所有表共置
SELECT create_distributed_table('orders',    'tenant_id');
SELECT create_distributed_table('customers', 'tenant_id', colocate_with => 'orders');
SELECT create_distributed_table('products',  'tenant_id', colocate_with => 'orders');
SELECT create_distributed_table('invoices',  'tenant_id', colocate_with => 'orders');

-- 以下 JOIN 完全在本地執行,零跨節點通訊
SELECT c.name, o.order_id, o.amount, i.invoice_number
FROM customers c
JOIN orders o ON c.tenant_id = o.tenant_id AND c.customer_id = o.customer_id
JOIN invoices i ON i.tenant_id = o.tenant_id AND i.order_id = o.order_id
WHERE c.tenant_id = 'tenant_abc'
  AND c.customer_id = 12345;
-- 路由到單一 Worker,零跨節點通訊

Colocation 的資料分布視覺化:

Tenant A (tenant_id = 'abc') → Shard Group 5 → Worker 2
  ├─ orders_102015      (Tenant A 的訂單)
  ├─ customers_102015   (Tenant A 的客戶)
  ├─ products_102015    (Tenant A 的產品)
  └─ invoices_102015    (Tenant A 的發票)

Tenant B (tenant_id = 'xyz') → Shard Group 12 → Worker 1
  ├─ orders_102022
  ├─ customers_102022
  ├─ products_102022
  └─ invoices_102022

查看 Colocation Group:

-- 確認各表的 Colocation Group
SELECT logicalrelid AS table_name, colocationid
FROM pg_dist_partition
ORDER BY colocationid, logicalrelid;

Schema-based Sharding(Citus 12+)

Citus 12 引入了基於 Schema 的分片機制,這是多租戶 SaaS 的重大改進。每個租戶擁有獨立的 PostgreSQL Schema,Citus 自動將整個 Schema 分配到對應 Worker:

-- 啟用 Schema-based Sharding
SET citus.enable_schema_based_sharding TO on;

-- 為每個租戶建立獨立 Schema
CREATE SCHEMA tenant_abc;
CREATE SCHEMA tenant_xyz;

-- 在 Schema 內建表(不需要呼叫 create_distributed_table!)
CREATE TABLE tenant_abc.orders (
    order_id    BIGINT PRIMARY KEY,
    amount      NUMERIC(12,2),
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE tenant_abc.customers (
    customer_id BIGINT PRIMARY KEY,
    name        TEXT NOT NULL,
    email       TEXT
);

-- Citus 自動將整個 tenant_abc schema 分配到某個 Worker
-- tenant_abc 內的所有表自動 Collocated!

Column-based vs Schema-based

特性Column-based(傳統)Schema-based(Citus 12+)
分片單元行(依分片鍵欄位值)Schema(整個 Schema 到一個 Worker)
設定複雜度每張表需呼叫 create_distributed_table只需建立 Schema
跨表隔離同一表混合多個租戶每個租戶有獨立 Schema
資料隔離邏輯隔離Schema 級隔離
適用規模租戶數百萬,每租戶資料少租戶數千,每租戶資料多
RLS 需求需要額外 RLS 設定Schema 天然隔離
搬移粒度Shard(行子集)整個 Schema

安裝與叢集設定

# Ubuntu/Debian 安裝 Citus(以 PG 16 為例)
curl https://install.citusdata.com/community/deb.sh | sudo bash
sudo apt-get install -y postgresql-16-citus-12.1

# 設定 shared_preload_libraries(必須,需重啟)
echo "shared_preload_libraries = 'citus'" >> /etc/postgresql/16/main/postgresql.conf
sudo systemctl restart postgresql
-- 在每個節點(Coordinator 和所有 Worker)執行
CREATE EXTENSION citus;

-- 在 Coordinator 上新增 Worker 節點
SELECT citus_add_node('worker1-hostname', 5432);
SELECT citus_add_node('worker2-hostname', 5432);
SELECT citus_add_node('worker3-hostname', 5432);

-- 驗證節點狀態
SELECT * FROM citus_get_active_worker_nodes();

-- 查看完整節點清單
SELECT nodeid, nodename, nodeport, isactive, noderole
FROM pg_dist_node
ORDER BY nodeid;

分散式 DDL 與限制

Citus 中的 DDL 會自動廣播到所有 Worker:

-- 自動應用到所有 Shard
ALTER TABLE orders ADD COLUMN notes TEXT;
CREATE INDEX CONCURRENTLY idx_orders_status ON orders(status);

-- 外鍵約束必須包含分片鍵
ALTER TABLE orders ADD CONSTRAINT fk_customer
    FOREIGN KEY (tenant_id, customer_id)
    REFERENCES customers(tenant_id, customer_id);
-- 注意:orders 和 customers 必須 Colocated

-- 不允許的操作
UPDATE orders SET customer_id = 99999 WHERE order_id = 1;
-- ERROR: modifying the partition column of a row is not allowed

Shard 管理:

-- 查看分散表設定
SELECT logicalrelid AS table_name, partmethod, partkey, colocationid
FROM pg_dist_partition
ORDER BY logicalrelid;

-- 查看 Shard 分布
SELECT s.logicalrelid, s.shardid, sp.nodename, sp.nodeport
FROM pg_dist_shard s
JOIN pg_dist_shard_placement sp ON s.shardid = sp.shardid
WHERE s.logicalrelid = 'orders'::regclass
ORDER BY s.shardid;

-- 調整 Shard 數量(建表前設定)
SET citus.shard_count = 64;  -- 預設 32
SELECT create_distributed_table('large_table', 'user_id');

-- 查詢特定記錄在哪個 Worker
SELECT get_shard_id_for_distribution_column('orders', 12345);

Shard 重新平衡

新增 Worker 後,需要重新平衡 Shard 分布:

-- 自動重新平衡
SELECT rebalance_table_shards('orders');

-- 手動搬移特定 Shard
SELECT citus_move_shard_placement(
    shardid,
    'source_worker', 5432,
    'target_worker', 5432
)
FROM pg_dist_shard_placement
WHERE nodename = 'source_worker'
LIMIT 5;

-- 查看重新平衡進度
SELECT * FROM get_rebalance_progress();

多租戶 SaaS 實戰

Citus 最成熟的使用場景是多租戶 SaaS,以 tenant_id 為統一分片鍵:

-- === Step 1: 建立分散表並共置 ===
SELECT create_distributed_table('tenants',   'tenant_id');
SELECT create_distributed_table('users',     'tenant_id', colocate_with => 'tenants');
SELECT create_distributed_table('orders',    'tenant_id', colocate_with => 'tenants');
SELECT create_distributed_table('products',  'tenant_id', colocate_with => 'tenants');

-- === Step 2: 建立參考表(跨租戶共用資料) ===
SELECT create_reference_table('payment_methods');
SELECT create_reference_table('shipping_zones');

-- === Step 3: 設定 Row Level Security ===
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
    USING (tenant_id = current_setting('app.current_tenant')::bigint);

-- === Step 4: 應用程式設定租戶 context ===
SET LOCAL app.current_tenant = '12345';
SELECT * FROM orders WHERE status = 'pending';
-- 自動過濾:只返回 tenant_id = 12345 的訂單

-- === Step 5: 管理員跨租戶查詢 ===
RESET app.current_tenant;
SELECT tenant_id, COUNT(*) AS order_count, SUM(amount) AS total
FROM orders
GROUP BY tenant_id
ORDER BY total DESC;

架構優勢:

┌─ 應用程式 ─┐      ┌─ Coordinator ─┐      ┌─ Workers ──────────┐
│            │      │               │      │                    │
│ SET tenant │─────►│ 解析 SQL      │─────►│ Worker 1: Tenant A │
│ → 查詢    │      │ + 路由到       │      │ Worker 2: Tenant B │
│            │      │   對應 Worker  │      │ Worker 3: Tenant C │
└────────────┘      └───────────────┘      └────────────────────┘

每個租戶的所有表資料(orders, customers, products)
都在同一個 Worker 上 → 零跨節點通訊

時序資料架構(Citus + 分割表)

Citus 可與 PostgreSQL 原生分割表結合,實現分散式時序架構——同時利用 Partition Pruning 和 Shard Pruning 的雙重裁剪:

-- 建立時序分散表(先分散後分割)
CREATE TABLE metrics (
    device_id   BIGINT NOT NULL,
    recorded_at TIMESTAMPTZ NOT NULL,
    metric_name TEXT NOT NULL,
    value       DOUBLE PRECISION,
    tags        JSONB
) PARTITION BY RANGE (recorded_at);

-- 將父表設為分散表
SELECT create_distributed_table('metrics', 'device_id');

-- 建立時間分割子表
CREATE TABLE metrics_2026_05 PARTITION OF metrics
    FOR VALUES FROM ('2026-05-01') TO ('2026-06-01');

CREATE TABLE metrics_2026_06 PARTITION OF metrics
    FOR VALUES FROM ('2026-06-01') TO ('2026-07-01');

-- 查詢效率極高:Partition Pruning + Shard Pruning 雙重裁剪
SELECT AVG(value)
FROM metrics
WHERE device_id = 1001                                    -- Shard Pruning
  AND recorded_at BETWEEN '2026-05-01' AND '2026-05-31';  -- Partition Pruning
-- 只訪問 metrics_2026_05 分割,且只在 device_id=1001 所在的 Worker 上執行

分散式交易

-- Citus 支援分散式交易(透過兩階段提交 2PC)
BEGIN;
INSERT INTO orders (tenant_id, order_id, amount)
VALUES (100, 9001, 150.00);
INSERT INTO order_items (tenant_id, order_id, product_id, qty)
VALUES (100, 9001, 5, 2);
COMMIT;
-- 若 Colocated,此交易在單一 Worker 本地執行(效能最佳)

-- 涉及多個 Worker 時自動使用 2PC
BEGIN;
UPDATE orders SET status = 'cancelled'
WHERE order_id IN (1, 2, 3, 4, 5);
-- 若這些 order_id 分布在不同 Worker,Citus 自動 2PC
COMMIT;

不支援的操作:

  1. 跨分片鍵的 UPDATE(無法在分片間移動行)
  2. 修改分散表的分片鍵欄位值
  3. 涉及多個非共置分散表的 FOR UPDATE

效能調優

-- 1. 啟用 Repartition Joins
SET citus.enable_repartition_joins = on;

-- 2. 調整平行查詢
SET citus.max_adaptive_executor_pool_size = 16;

-- 3. 分析查詢計畫,識別跨節點資料移動
EXPLAIN (ANALYZE, VERBOSE)
SELECT customer_id, SUM(amount)
FROM orders
GROUP BY customer_id
HAVING SUM(amount) > 10000;
-- 觀察是否有 Repartition 或 Broadcast 步驟

-- 4. Worker 內部平行度(各 Worker 的 postgresql.conf)
-- max_parallel_workers_per_gather = 4

-- 5. 複合索引策略(分片鍵必須在索引中)
CREATE INDEX idx_orders_customer_created
ON orders (customer_id, created_at DESC);

-- 6. Coordinator 前端建議使用 PgBouncer 做連線池

監控與除錯

-- 查看分散式查詢的執行計畫
EXPLAIN SELECT COUNT(*) FROM orders WHERE customer_id = 12345;

-- 查看 Coordinator 活躍連線
SELECT * FROM citus_dist_stat_activity;

-- 查看 Worker 任務執行
SELECT * FROM citus_worker_stat_activity;

-- 查看各 Shard 資料大小
SELECT table_name, shard_id, shard_size
FROM citus_shards
WHERE table_name = 'orders'::regclass
ORDER BY shard_size DESC;

-- 慢查詢分析
SELECT * FROM citus_stat_statements
ORDER BY total_time DESC LIMIT 20;

-- 節點健康狀態
SELECT nodename, nodeport, isactive, shouldhaveshards
FROM pg_dist_node;

高可用架構

Citus 本身不提供節點層面的高可用,需整合 PostgreSQL 複寫與故障轉移工具:

┌──────────────────────────────────────────────────────────┐
│                     Citus HA 架構                         │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  Coordinator Primary ──Streaming Replication──► Standby  │
│       │                                                  │
│  (Patroni / pg_auto_failover 管理 Coordinator HA)        │
│                                                          │
│  Worker 1 Primary ──► Worker 1 Standby                   │
│  Worker 2 Primary ──► Worker 2 Standby   (各自獨立 HA)  │
│  Worker N Primary ──► Worker N Standby                   │
│                                                          │
└──────────────────────────────────────────────────────────┘
-- 查看各節點健康
SELECT nodename, nodeport, isactive FROM pg_dist_node;

-- Worker 故障後標記為不活躍
SELECT citus_disable_node('failed_worker', 5432);

-- 恢復後重新啟用
SELECT citus_activate_node('recovered_worker', 5432);

Citus vs 其他方案

Citus vs Cloud SQL / AlloyDB

維度CitusCloud SQL / AlloyDB
擴展模式水平分片(Scale-Out)垂直擴展 + 讀取副本
PG 相容性高度相容,有分散式限制完全相容
管理複雜度高(需設計分片策略)低(全託管)
最大資料量近乎無限(加 Worker)受單機規格限制
寫入擴展是(多 Writer)否(單 Primary)
跨節點 JOIN受限(需 Colocation)完全支援
適用場景超大規模多租戶、分析一般 OLTP

Citus vs Google Spanner

維度CitusSpanner
全球分散需額外設計原生全球分散
強一致性本地強一致全球強一致(TrueTime)
SQL 相容性PostgreSQL SQLSpanner SQL
自動 Sharding半自動(需設計分片鍵)完全自動
費用較低(可自建)極高
生態系PostgreSQL 完整生態獨立生態

選擇決策流程

需要分散式資料庫?
├─ 否 → 單機 PostgreSQL(+ HA 複寫)
└─ 是
    ├─ 需要全球強一致性?
    │   ├─ 是 → Google Spanner
    │   └─ 否
    │       ├─ 有明確的 tenant_id 或分片鍵?
    │       │   ├─ 是 → Citus(效能最佳)
    │       │   └─ 否 → AlloyDB 或重新設計 Schema
    │       ├─ 可接受 PG 相容性限制?
    │       │   ├─ 是 → Citus
    │       │   └─ 否 → AlloyDB 或升級單機規格
    │       └─ 預算有限且可自建?
    │           ├─ 是 → 自建 Citus
    │           └─ 否 → Azure Cosmos DB for PostgreSQL

版本演進

版本年份重要功能
Citus 5.x2015初始開源版本,基礎 Hash 分片
Citus 7.x2018分散式 DDL、Append Distribution 改進
Citus 9.x2019微軟收購,效能大幅提升
Citus 10.x2021完全開源(含原企業版功能),Columnar Storage
Citus 11.x2022支援所有節點直連
Citus 12.x2023Schema-based Sharding
Citus 13.x2025PG 17 支援、分散式查詢效能提升

總結

Citus 作為 PostgreSQL 的分散式擴展,提供了一條不離開 PG 生態的水平擴展之路。掌握以下核心觀念,就能駕馭 Citus 的分散式威力:

  1. 分片鍵決定一切——選對分片鍵(通常是 tenant_id),Router Query 的效能等同單機 PG
  2. Colocation 是效能關鍵——共置的表可以在本地 JOIN,避免跨節點資料移動
  3. 參考表解決維度 JOIN——小型查詢表複製到每個 Worker,與任何表本地 JOIN
  4. Schema-based Sharding(Citus 12+)——多租戶 SaaS 的更直覺選擇,Schema 級隔離
  5. 不是所有場景都需要分散式——資料量 < 2TB 時,單機 PG + HA 通常是更好的選擇

至此,PostgreSQL 完全指南 50 篇系列全部完成。從第 1 篇的安裝與基礎 SQL,到這一篇的分散式擴展,我們走過了 PostgreSQL 從入門到精通的完整旅程。希望這個系列能成為你在 PostgreSQL 世界中持續前行的堅實基礎。

BenZ Software Developer

熱愛技術的軟體開發者,在這裡分享程式開發經驗與學習筆記。

本週主打

AI 自動化入門包

你每天手動在做的那些煩事,其實 AI 可以自己跑。這份給你 10 個照著做就會的自動化工作流 + 50 個複製即用的提示詞,不用會寫程式。

看看這個產品 →