PostgreSQL Sharding:扩展关系型数据库
发布: (2026年2月5日 GMT+8 12:08)
4 min read
原文: Dev.to
Source: Dev.to
为什么使用分片?
| 方面 | 好处 | 权衡 |
|---|---|---|
| 可扩展性 | 随着节点增加线性增长 | 运维复杂度提升 |
| 查询简洁性 | 单分片读取速度快 | 跨分片连接需要编排 |
| 数据局部性 | 用户通常访问自己的分片 | 当分片不均衡增长时需要重新平衡数据 |
| 故障隔离 | 单个分片故障 ≠ 整体宕机 | 需要健壮的监控和故障转移机制 |
关键洞见: 切勿仅凭便利性来选择分片键;它必须保证数据均匀分布,并与最常用的查询模式保持一致。
分片策略
| Strategy | Description |
|---|---|
| Range‑based | 行通过分片键的连续范围划分(例如,用户 ID)。 |
| Hash‑based | 哈希函数均匀分配行,避免热点。 |
| Directory‑based | 查找服务将每个键映射到特定分片(在 Citus 中常见)。 |
基于范围的示例(PostgreSQL pg_partman)
-- Create a parent table
CREATE TABLE users (
id BIGINT NOT NULL,
name TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
PRIMARY KEY (id)
) PARTITION BY RANGE (id);
-- Create partitions (shards)
CREATE TABLE users_0_9999 PARTITION OF users FOR VALUES FROM (0) TO (10000);
CREATE TABLE users_10000_19999 PARTITION OF users FOR VALUES FROM (10000) TO (20000);
基于哈希的示例(Citus 扩展)
-- Enable the Citus extension
CREATE EXTENSION IF NOT EXISTS citus;
-- Create a distributed (sharded) table
SELECT create_distributed_table('users', 'id');
基于目录的配置(YAML)
sharding:
enabled: true
shardKey: "userId"
shards:
- name: shardA
range: "0-2499"
- name: shardB
range: "2500-4999"
- name: shardC
range: "5000-7499"
- name: shardD
range: "7500-9999"
使用 Citus 的实现步骤
-
安装 Citus
psql -c "CREATE EXTENSION IF NOT EXISTS citus;" -
创建分布式表
SELECT create_distributed_table('users', 'id'); -
监控分片健康
- 监控每个节点的 CPU、延迟和复制滞后。
- 使用仪表盘或兼容 Prometheus 的导出器。
-
自动化再平衡
- 通过 Citus 的
rebalance_table_shards或自定义脚本将热点范围迁移到新节点。
- 通过 Citus 的
-
按分片备份
- 对每个分片执行逻辑备份(
pg_dump),以避免跨分片恢复的复杂性。
- 对每个分片执行逻辑备份(
陷阱与最佳实践
- 分片键选择: 必须确保均匀分布,并与常用查询谓词保持一致。
- 跨分片查询: 预期延迟更高;设计模式时应尽量减少跨分片的连接。
- 运维开销: 节点越多,监控、打补丁和容量规划的工作就越多。
- 数据重新平衡: 计划使用自动化工具;手动迁移可能导致停机。
- 测试: 在预生产环境中验证性能和故障场景后再进行正式上线。
入门
- 原型: 在使用 Citus 的预发布环境中部署一个小规模的分片集群。
- 测量: 记录查询延迟、吞吐量以及节点资源利用率。
- 迭代: 根据观察到的流量模式,优化分片键、分区策略和监控方案。
PostgreSQL 分片使团队能够突破单实例的限制进行横向扩展,但这需要严格的设计、细致的监控以及周到的运维实践。请从明确的分片键开始,原型化单一策略,并根据真实流量进行迭代。