# ha/citus

> 13 节点 Citus 分布式 PostgreSQL 集群，1 协调组 + 5 工作组高可用配置，提供水平扩展与分片能力

---

LLMS index: [llms.txt](/llms.txt)

---

`ha/citus` 配置模板部署一套完整的 **Citus 分布式 PostgreSQL 集群**，包含 1 个基础设施节点、1 组协调节点和 5 组工作节点（共 12 个 Citus 节点），提供透明的水平扩展与数据分片能力。


--------

## 配置概览

- 配置名称： `ha/citus`
- 节点数量： 13 节点（1 基础设施 + 1 协调组 × 2 + 5 工作组 × 2）
- 配置说明：Citus 分布式 PostgreSQL 高可用集群
- 适用系统：`el8`, `el9`, `el10`, `d12`, `d13`, `u22`, `u24`, `u26`
- 适用架构：`x86_64`
- 相关配置：[`meta`](/docs/conf/meta/)，[`ha/trio`](/docs/conf/trio/)

启用方式：

```bash
./configure -c ha/citus
```

> 备注：这是一个 13 节点模板，您需要在生成配置后修改各节点的 IP 地址


--------

## 配置内容

源文件地址：[`pigsty/conf/ha/citus.yml`](https://github.com/pgsty/pigsty/blob/main/conf/ha/citus.yml)

<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#==============================================================#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># File      :   citus.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># Desc      :   13-node Citus (6-group Distributive) Config Template</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># Ctime     :   2020-05-22</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># Mtime     :   2025-01-20</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># Docs      :   https://pigsty.io/docs/conf/citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#==============================================================#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># This is the config template for Citus Distributive Cluster</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># tutorial: https://pigsty.io/docs/pgsql/kernel/citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># we will use the local repo for cluster bootstrapping</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># Topology:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   - pg-citus0: coordinator (10.10.10.10)         VIP: 10.10.10.19</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   - pg-citus1: worker group 1 (10.10.10.21, 22)  VIP: 10.10.10.29</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   - pg-citus2: worker group 2 (10.10.10.31, 32)  VIP: 10.10.10.39</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   - pg-citus3: worker group 3 (10.10.10.41, 42)  VIP: 10.10.10.49</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   - pg-citus4: worker group 4 (10.10.10.51, 52)  VIP: 10.10.10.59</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   - pg-citus5: worker group 5 (10.10.10.61, 62)  VIP: 10.10.10.69</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   - pg-citus6: worker group 6 (10.10.10.71, 72)  VIP: 10.10.10.79</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># Usage:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   curl https://repo.pigsty.io/get | bash</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   ./configure -c citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c">#   ./deploy.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">all</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">children</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">infra</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">hosts</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">10.10.10.10</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">infra_seq</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w"> </span>}}}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">etcd</span><span class="p">:</span><span class="w">  </span>{<span class="w"> </span><span class="nt">hosts</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">10.10.10.10</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">etcd_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1  }}, vars</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">etcd_cluster</span><span class="p">:</span><span class="w"> </span><span class="l">etcd }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg-meta</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">hosts</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">10.10.10.10</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">primary } }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">vars</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="l">pg-meta</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_users</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- {<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="nt">dbuser_meta ,password</span><span class="p">:</span><span class="w"> </span><span class="nt">DBUser.Meta   ,pgbouncer</span><span class="p">:</span><span class="w"> </span><span class="nt">true ,roles</span><span class="p">:</span><span class="w"> </span><span class="nt">[dbrole_admin   ] ,comment</span><span class="p">:</span><span class="w"> </span><span class="l">pigsty admin user }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_databases</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">meta</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">baseline</span><span class="p">:</span><span class="w"> </span><span class="l">cmdb.sql</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">comment</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;pigsty meta database&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">schemas</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">pigsty]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">extensions</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="l">postgis, vector ]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_crontab</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s1">&#39;00 01 * * * /pg/bin/pg-backup full&#39;</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="c"># make a full backup every day 1am</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c"># pg-citus: 6 cluster groups, 12 nodes total</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg-citus</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">hosts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># coordinator (group 0) on infra node</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.21</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">0, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus1 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.29/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">primary }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.22</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">0, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus1 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.29/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">replica }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># worker group 2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.31</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus2 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.39/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">primary }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.32</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus2 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.39/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">replica }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># worker group 3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.41</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus3 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.49/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">primary }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.42</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus3 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.49/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">replica }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># worker group 4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.51</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">3, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus4 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.59/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">primary }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.52</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">3, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus4 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.59/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">replica }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># worker group 5</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.61</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">4, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus5 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.69/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">primary }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.62</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">4, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus5 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.69/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">replica }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># worker group 6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.71</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">5, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus6 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.79/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">1, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">primary }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">10.10.10.72</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">pg_group</span><span class="p">:</span><span class="w"> </span><span class="nt">5, pg_cluster</span><span class="p">:</span><span class="w"> </span><span class="nt">pg-citus6 ,pg_vip_address</span><span class="p">:</span><span class="w"> </span><span class="nt">10.10.10.79/24 ,pg_seq</span><span class="p">:</span><span class="w"> </span><span class="nt">2, pg_role</span><span class="p">:</span><span class="w"> </span><span class="l">replica }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">vars</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_mode</span><span class="p">:</span><span class="w"> </span><span class="l">citus                           </span><span class="w"> </span><span class="c"># pgsql cluster mode: citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_shard</span><span class="p">:</span><span class="w"> </span><span class="l">pg-citus                       </span><span class="w"> </span><span class="c"># citus shard name: pg-citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_primary_db</span><span class="p">:</span><span class="w"> </span><span class="l">citus                     </span><span class="w"> </span><span class="c"># primary database used by citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_dbsu_password</span><span class="p">:</span><span class="w"> </span><span class="l">DBUser.Postgres        </span><span class="w"> </span><span class="c"># enable dbsu password access for citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_extensions</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="l">citus, postgis, pgvector, topn, pg_cron, hll ]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_libs</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;citus, pg_cron, pg_stat_statements&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_users</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>{<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="nt">dbuser_citus ,password</span><span class="p">:</span><span class="w"> </span><span class="nt">DBUser.Citus ,pgbouncer</span><span class="p">:</span><span class="w"> </span><span class="nt">true ,roles</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="l">dbrole_admin ] }]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_databases</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>{<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="nt">citus ,owner</span><span class="p">:</span><span class="w"> </span><span class="nt">dbuser_citus ,extensions</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="l">citus, vector, topn, pg_cron, hll ] }]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_parameters</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">cron.database_name</span><span class="p">:</span><span class="w"> </span><span class="l">citus</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">citus.node_conninfo</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;sslrootcert=/pg/cert/ca.crt sslmode=verify-full&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_hba_rules</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- {<span class="w"> </span><span class="nt">user</span><span class="p">:</span><span class="w"> </span><span class="nt">&#39;all&#39; ,db</span><span class="p">:</span><span class="w"> </span><span class="nt">all  ,addr</span><span class="p">:</span><span class="w"> </span><span class="nt">127.0.0.1/32  ,auth</span><span class="p">:</span><span class="w"> </span><span class="nt">ssl ,title</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;all user ssl access from localhost&#39;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- {<span class="w"> </span><span class="nt">user</span><span class="p">:</span><span class="w"> </span><span class="nt">&#39;all&#39; ,db</span><span class="p">:</span><span class="w"> </span><span class="nt">all  ,addr</span><span class="p">:</span><span class="w"> </span><span class="nt">intra         ,auth</span><span class="p">:</span><span class="w"> </span><span class="nt">ssl ,title</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;all user ssl access from intranet&#39;</span><span class="w">  </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_vip_enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">pg_crontab</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s1">&#39;00 01 * * * /pg/bin/pg-backup full&#39;</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="c"># make a full backup every day 1am</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">vars</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c"># INFRA : https://pigsty.io/docs/infra/param</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="l">v4.5.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">admin_ip</span><span class="p">:</span><span class="w"> </span><span class="m">10.10.10.10</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">region</span><span class="p">:</span><span class="w"> </span><span class="l">default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">infra_portal</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">home </span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">domain</span><span class="p">:</span><span class="w"> </span><span class="l">i.pigsty }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c"># NODE : https://pigsty.io/docs/node/param</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">nodename_overwrite</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">node_repo_modules</span><span class="p">:</span><span class="w"> </span><span class="l">node,infra,pgsql</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">node_tune</span><span class="p">:</span><span class="w"> </span><span class="l">oltp</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c"># PGSQL : https://pigsty.io/docs/pgsql/param</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg_version</span><span class="p">:</span><span class="w"> </span><span class="m">18</span><span class="w">  </span><span class="c"># PostgreSQL 14-18</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg_conf</span><span class="p">:</span><span class="w"> </span><span class="l">oltp.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg_packages</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="l">pgsql-main, pgsql-common ]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c"># PASSWORD : https://pigsty.io/docs/setup/security/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c">#----------------------------------------------#</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">grafana_admin_password</span><span class="p">:</span><span class="w"> </span><span class="l">pigsty</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">grafana_view_password</span><span class="p">:</span><span class="w"> </span><span class="l">DBUser.Viewer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg_admin_password</span><span class="p">:</span><span class="w"> </span><span class="l">DBUser.DBA</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg_monitor_password</span><span class="p">:</span><span class="w"> </span><span class="l">DBUser.Monitor</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pg_replication_password</span><span class="p">:</span><span class="w"> </span><span class="l">DBUser.Replicator</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">patroni_password</span><span class="p">:</span><span class="w"> </span><span class="l">Patroni.API</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">haproxy_admin_password</span><span class="p">:</span><span class="w"> </span><span class="l">pigsty</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">minio_secret_key</span><span class="p">:</span><span class="w"> </span><span class="l">S3User.MinIO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">etcd_root_password</span><span class="p">:</span><span class="w"> </span><span class="l">Etcd.Root</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">...</span><span class="w">
</span></span></span></code></pre></div>


--------

## 集群拓扑

此配置部署一套完整的 Citus 分布式集群，拓扑结构如下：

| 集群            | 节点 | IP 地址           | VIP         | 角色            |
|---------------|----|-----------------|-------------|---------------|
| **pg-meta**   | 1  | 10.10.10.10     | -           | 基础设施 + CMDB   |
| **pg-citus1** | 2  | 10.10.10.21, 22 | 10.10.10.29 | 协调节点（group 0） |
| **pg-citus2** | 2  | 10.10.10.31, 32 | 10.10.10.39 | 工作节点（group 1） |
| **pg-citus3** | 2  | 10.10.10.41, 42 | 10.10.10.49 | 工作节点（group 2） |
| **pg-citus4** | 2  | 10.10.10.51, 52 | 10.10.10.59 | 工作节点（group 3） |
| **pg-citus5** | 2  | 10.10.10.61, 62 | 10.10.10.69 | 工作节点（group 4） |
| **pg-citus6** | 2  | 10.10.10.71, 72 | 10.10.10.79 | 工作节点（group 5） |

**架构说明**：

- **pg-meta**：基础设施节点，运行 Grafana、VictoriaMetrics、etcd 等组件，同时部署一个独立的 CMDB 数据库
- **pg-citus1**：Citus 协调节点（group 0），负责接收客户端查询并路由到工作节点，1 主 1 从高可用配置
- **pg-citus2~6**：Citus 工作节点（group 1~5），存储分片数据，每组 1 主 1 从，通过 Patroni 实现自动故障转移
- **VIP**：每个节点组配置 L2 VIP，由 `vip-manager` 管理，确保故障转移时客户端连接自动切换


--------

## 配置解读

`ha/citus` 模板部署生产级 Citus 分布式集群，适合需要水平扩展的大规模数据场景。

**关键特性**：

- **水平扩展**：5 个工作组可线性扩展存储和计算能力
- **高可用**：每个工作组 1 主 1 从，支持自动故障转移
- **L2 VIP**：每组配置虚拟 IP，故障切换对应用透明
- **SSL 加密**：节点间通信使用 SSL 证书加密
- **透明分片**：数据自动分布到多个工作节点

**预装扩展**：

```yaml
pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]
pg_libs: 'citus, pg_cron, pg_stat_statements'
```

**安全配置**：

- 启用 `pg_dbsu_password`，允许超级用户密码访问（Citus 节点间通信需要）
- HBA 规则要求所有连接使用 SSL 认证
- 节点间使用证书验证：`sslmode=verify-full`


--------

## 部署步骤

```bash
# 1. 下载 Pigsty
curl -fsSL https://repo.pigsty.cc/get | bash; cd ~/pigsty

# 2. 使用 ha/citus 配置模板
./configure -c ha/citus

# 3. 修改 IP 地址和密码
vi pigsty.yml

# 4. 部署完整集群
./deploy.yml
```

部署完成后，Citus 会自动注册所有工作节点。可通过以下命令验证：

```sql
-- 连接到任意协调节点
psql -h 10.10.10.29 -U dbuser_citus -d citus

-- 查看工作节点状态
SELECT * FROM citus_get_active_worker_nodes();

-- 查看分片分布
SELECT * FROM citus_shards;
```


--------

## 使用示例

**创建分布式表**：

```sql
-- 创建表
CREATE TABLE events (
    tenant_id INT,
    event_id BIGSERIAL,
    event_time TIMESTAMPTZ DEFAULT now(),
    payload JSONB,
    PRIMARY KEY (tenant_id, event_id)
);

-- 按 tenant_id 分片
SELECT create_distributed_table('events', 'tenant_id');

-- 插入数据（自动路由到对应分片）
INSERT INTO events (tenant_id, payload)
VALUES (1, '{"type": "click"}');

-- 查询（自动并行执行）
SELECT tenant_id, count(*)
FROM events
GROUP BY tenant_id;
```

**创建引用表**（小表复制到所有节点）：

```sql
CREATE TABLE tenants (
    tenant_id INT PRIMARY KEY,
    name TEXT
);

SELECT create_reference_table('tenants');
```


--------

## 适用场景

- **多租户 SaaS**：按租户 ID 分片，实现租户数据隔离和并行查询
- **实时分析**：大规模事件数据的实时聚合分析
- **时序数据**：结合 TimescaleDB 处理海量时序数据
- **水平扩展**：单表数据量超过单机容量时的扩展方案


--------

## 注意事项

- **PostgreSQL 版本**：Citus 支持 PostgreSQL 14~18，此模板默认使用 PG18
- **分布列选择**：合理选择分布列（通常是租户 ID 或时间戳）对性能至关重要
- **跨分片限制**：外键约束必须包含分布列，部分 DDL 操作有限制
- **网络要求**：`pg_vip_interface` 默认为 `auto`，特殊网络环境可显式指定网卡
- **架构限制**：Citus 扩展不支持 ARM64 架构
