← Back to list

初探 Citus 並實現多租戶

Citus 是一個100%開源的 PostgreSQL 擴充功能,能橫向擴展(scale-out) PostgreSQL。 你可以從單一節點開始,逐步擴展成分散式叢集。 因為 Citus 是擴充功能(非分支),會保留原生的 PostgreSQL…

RiCo 技術農場 in RiCosNote · 2026-05-21 00:17 · 0 claps · 11.1 min read
#net-core #postgresql #ai #citusdata #data
Open on Medium ↗
Wiki topics: AI · AI · General

初探 Citus 並實現多租戶

Citus 是一個100%開源的 PostgreSQL 擴充功能,能橫向擴展(scale-out) PostgreSQL。 你可以從單一節點開始,逐步擴展成分散式叢集。 因為 Citus 是擴充功能(非分支),會保留原生的 PostgreSQL 相容性、功能、生態系統工具和擴充功能。

主要功能:

  • 分散式資料表(基於row或schema的分片)
  • 維度與共享資料的參考表
  • 共置聯結與分散式查詢規劃器
  • 跨worker的平行查詢執行
  • 柱狀儲存選項
  • 來自任意節點的查詢(自 Citus 11.0+)

架構如下圖

協調者(Coordinator)對於每個查詢,要麼選擇以下其中之一:

  • 將其路由至單一worker(當所有所需資料皆位於該worker時),或
  • 在worker之間將其平行化 (當資料跨分區時)

Citus 支援兩種分片(row base、schema base)模型,每種都有不同的取捨

Row base簡單說就是所有租戶共用相同資料表(如Order),但透過 tenant_id 做分片,citus會依tenant_id做hash,將同一租戶資料放在相同worker,這可避免掃全叢集,稱為Query Locality(查詢區域性),大規模SaaS都採該模式為主流,但缺點就是租戶不能客製schema。

Schema base簡單說每個租戶有自己的 schema(非共用相同資料表),每租戶有mini database但底層相同為PostgreSQL cluster,主要缺點是migration麻煩、metadata可能爆炸(租戶數量*資料表數量)。

資料表類型如下圖

共置(Colocation)

將相關資料表的分片放在一起(相同的雜湊映射)以便進行本地連接,可減少跨節點資料移動,如果分片規則不同,就需要跨節點搬資料(Shuffle Data),大量的資料交換就是Repartition Join,這也是使用分散式資料庫最高成本操作(大部分瓶頸都是network I/O),一定要盡力避免(小表可善用reference table)。

查詢平行性與執行流程

協調器會將多分片查詢分解成每個分片的任務,優先下放Query至worker(非拉資料回來至協調器處理)。Citus效能處理是優先避免跨節點,而非最大化平行處理,任務執行嘗試平衡:

  • 並行 (每個工作者的平行連線數)
  • 連線負荷 (緩慢啟動提升)
  • 工作者資源節省 (閒置連線上限)

簡單理解,協調器會將SQL拆解多個小任務,並分配下放到相對應worker執行,同時盡量避免跨節點進行資料搬移,四大原則如下圖

下面我參考 Docker (Mac or Linux) 快速建立 Citus cluster並簡單使用ASP.NET Core MVC測試多租戶呈現不同portal

curl -L https://raw.githubusercontent.com/citusdata/docker/master/docker-compose.yml > docker-compose.yml
COMPOSE_PROJECT_NAME=citus POSTGRES_PASSWORD=root docker compose up -d

# scale-out worker
docker compose up -d --scale worker=2

DROP TABLE questions CASCADE;
DROP TABLE tenants CASCADE;

CREATE TABLE tenants (
    id uuid NOT NULL,
    domain text NOT NULL,
    name text NOT NULL,
    description text NOT NULL,
    created_at timestamptz NOT NULL,
    updated_at timestamptz NOT NULL
);

CREATE TABLE questions (
    id uuid NOT NULL,
    tenant_id uuid NOT NULL,
    title text NOT NULL,
    votes int NOT NULL,
    created_at timestamptz NOT NULL,
    updated_at timestamptz NOT NULL
);

ALTER TABLE tenants ADD PRIMARY KEY (id);

-- 要加入 tenant_id,Unique要在shard成立
ALTER TABLE questions ADD PRIMARY KEY (id, tenant_id); 

 -- Citus 使用租戶ID 進行分片 row base
 SELECT create_distributed_table('tenants', 'id');
 SELECT create_distributed_table('questions', 'tenant_id');

-- 驗證partmethod是否為h : Hash Distributed ,確認為分散式資料表
-- n : Reference Table
SELECT
    logicalrelid::regclass AS table_name,
    partmethod,
    partkey
FROM pg_dist_partition;

-- 也可透過citus_tables確認
-- 規模= 小型 shard數:32 ,中型 shard數:64, 大型 shard數:128~256
SELECT *
FROM citus_tables;

-- 確認所有worker nodes
SELECT * FROM citus_get_active_worker_nodes();

-- Rebalance Shards(告訴citues 自動搬 shard),如果後面有新增work,PRD建議離峰做
-- shard size 建議 1 ~ 10 GB,過大容易形成災難
SELECT rebalance_table_shards();

-- Rebalance 策略
SELECT *
FROM pg_dist_rebalance_strategy;

-- 查shard, hash range
SELECT
    shardid,
    logicalrelid::regclass,
    shardminvalue,
    shardmaxvalue
FROM pg_dist_shard;

-- 查看 shard 在哪個 worker
SELECT
    p.logicalrelid::regclass AS table_name,
    s.shardid,
    n.nodename,
    n.nodeport
FROM pg_dist_shard s
JOIN pg_dist_placement dp
    ON s.shardid = dp.shardid
JOIN pg_dist_node n
    ON dp.groupid = n.groupid
JOIN pg_dist_partition p
    ON s.logicalrelid = p.logicalrelid
ORDER BY table_name, shardid;

-- fake data
 INSERT INTO tenants VALUES (
        'c620f7ec-6b49-41e0-9913-08cfe81199af', 
        'rico.local',
        'rico test',
        'Ask anything code-related!',
        now(),
        now());

    INSERT INTO tenants VALUES (
        'b8a83a82-bb41-4bb3-bfaa-e923faab2ca4', 
        'fifi.local',
        'Database Questions',
        'Figure out why your connection string is broken.',
        now(),
        now());

    INSERT INTO questions VALUES (
        '347b7041-b421-4dc9-9e10-c64b8847fedf',
        'c620f7ec-6b49-41e0-9913-08cfe81199af',
        'How do you build apps in ASP.NET Core?',
        1,
        now(),
        now());

    INSERT INTO questions VALUES (
        'a47ffcd2-635a-496e-8c65-c1cab53702a7',
        'b8a83a82-bb41-4bb3-bfaa-e923faab2ca4',
        'Using postgresql for multitenant data?',
        2,
        now(),
        now());

Demo:

[embed]

VS Code x GitHub Copilot — AI 企業級協作開發實戰與應用

💯Rico技術學院

reference:

[embed]GitHub - citusdata/citus: Distributed PostgreSQL as an extension Distributed PostgreSQL as an extension. Contribute to citusdata/citus development by creating an account on GitHub.github.com

[embed]ASP.NET - Citus 13.0.1 documentation Docs for the Citus open source extension to Postgres. Citus gives you Postgres at any scale-from a single node to a…docs.citusdata.com

[embed]Ubuntu or Debian - Citus 13.0.1 documentation Docs for the Citus open source extension to Postgres. Citus gives you Postgres at any scale-from a single node to a…docs.citusdata.com

[embed]Docker (Mac or Linux) - Citus Docs 8.1 documentation This section describes setting up a Citus cluster on a single machine using docker-compose. Note The Docker image is…docs.citusdata.com

[embed]Citus Overview - Citus for PostgreSQL Learn what Citus is and the core architecture concepts including nodes, sharding models, table types, shards…learn.microsoft.com

[embed]Scalable Real-Time Product Search Using PostgreSQL with Citus - Citus for PostgreSQL Learn how to build scalable real-time product search by using PostgreSQL with Citus so you can handle large catalogs.learn.microsoft.com

[embed]Sharding a Multitenant App with PostgreSQL - Citus for PostgreSQL Learn how to shard a multitenant app with PostgreSQL and Citus so you can scale your SaaS application efficiently.learn.microsoft.com

[embed]擴展 PostgreSQL 以支援 8 億名 ChatGPT 使用者 深入瞭解 OpenAI 如何透過使用複本、快取、速率限制和工作負載隔離,將 PostgreSQL 擴展到每秒數百萬次查詢。openai.com

[embed]

[embed]GitHub - nbarbettini/QuestionExchange: Multi-tenant application architecture with ASP.NET Core 2.0… Multi-tenant application architecture with ASP.NET Core 2.0 + SaasKit + PostgreSQL + Citus …github.com


메타데이터
post_id
b6967cf69737
slug
初探-citus-並實現多租戶-b6967cf69737
url
https://medium.com/ricos-note/%E5%88%9D%E6%8E%A2-citus-%E4%B8%A6%E5%AF%A6%E7%8F%BE%E5%A4%9A%E7%A7%9F%E6%88%B6-b6967cf69737
canonical_url
https://medium.com/ricos-note/%E5%88%9D%E6%8E%A2-citus-%E4%B8%A6%E5%AF%A6%E7%8F%BE%E5%A4%9A%E7%A7%9F%E6%88%B6-b6967cf69737
author_url
https://medium.com/@iamrico1
status
ok
fetched_at
2026-07-12 01:39:19