17.4 比较分布式候选
候选比较的第一步,是保留“不分布”作为对照组。
如果表格只有三种分布式产品,团队会被迫在它们之间选一个;如果加入:
optimized primary
offline replica
independent analytical PostgreSQL
materialized summary很多问题会暴露为负载隔离或数据粒度问题,而不是横向分片问题。
本节不替读者宣布一个普遍赢家,而是建立同口径的比较方法。
17.4.1 PostgreSQL 扩展、兼容数据库与专用分析系统
候选地图
可以按“离 PostgreSQL 原生语义有多远”分层:
Layer 0: same PostgreSQL instance
indexes / partitions / parallel query / summaries
Layer 1: same physical PostgreSQL data
read replica / offline replica
Layer 2: another PostgreSQL data copy
logical replication / CDC / ETL to analytical PostgreSQL
Layer 3: PostgreSQL extension or federation
postgres_fdw / Citus / workload-specific extensions
Layer 4: PostgreSQL-wire or SQL-compatible distributed database
separate storage, transaction and operations implementation
Layer 5: specialized analytical system
columnar/vectorized engine, separate ingestion and lifecycle层数越高不表示越先进,只表示需要重新验证的语义越多。
对照组:优化后的 PostgreSQL
它应包含:
- 正确 schema 与统计信息;
- 代表性索引和 partition pruning;
- 并行计划与并发预算;
- 合理物化/汇总;
- workload guardrails;
- 当前硬件与一个可行纵向规格;
- offline replica 或独立分析副本候选。
若分布式候选只比未经调优的原表扫描快,比较没有意义。
postgres_fdw:联邦访问与机制实验
postgres_fdw 把远端 PostgreSQL 表映射为 foreign table:
CREATE EXTENSION
-> CREATE SERVER
-> CREATE USER MAPPING
-> CREATE FOREIGN TABLE / IMPORT FOREIGN SCHEMA
-> SELECT / DML它能做:
- 远端过滤和列裁剪;
- 某些 JOIN/聚合下推;
- 外表分区;
- 联邦读取;
- 迁移期间的过渡;
- 把远端数据物化到本地;
- 显示远端 SQL 和数据流。
它不应被默认理解为一个完整的透明分布式数据库。路由、rebalance、全局
约束、协调端 HA、全局备份点和很多运维职责仍需自行设计。PostgreSQL 18 的
postgres_fdw 远端事务也不支持 prepare 为两阶段提交。
本章用它是因为机制透明:
Foreign Scan
Remote SQL
actual rows
user mapping
server failure都能直接观察。它是很好的教学镜子,不是本章对生产选型的默认推荐。
Citus:PostgreSQL 扩展式分片候选
Citus 把表区分为 distributed、reference、local 等类型,以分布列决定行的 放置;相关表按相同分布键 colocate 后,单租户查询和某些 JOIN 可以在一组 共置分片上执行。跨租户聚合则可由 worker 产生 partial result,再由协调端 合并。
这使它适合评估:
multi-tenant workload with tenant-local transactions
real-time aggregate workload with decomposable computation
PostgreSQL ecosystem continuity但分布键选择成为 schema 与查询合同。Citus 官方 Choosing Distribution Column 强调 tenant/entity key、co-location 与跨节点数据移动之间的关系;小型共享 维表可评估 reference table。
需要验证:
- row-based 还是 schema-based sharding;
- distribution column 是否出现在 PK/FK/查询;
- colocated tables 与 reference tables;
- 单租户与全局查询比例;
- rebalance 与大租户隔离;
- coordinator/worker HA;
- distributed DDL;
- backup/restore;
- 版本升级和扩展组合;
- Pigsty L1 的实际拓扑。
本章 loopback FDW 的“同分片 JOIN 未下推”不能直接外推为 Citus 行为;它只 提醒读者对目标产品的目标 SQL 看实际计划。
PostgreSQL-compatible distributed database
这类系统可能支持 PostgreSQL wire protocol、部分 SQL、驱动和工具,让迁移 起步更容易。必须拆开“兼容”:
wire protocol
parser syntax
catalog shape
data types
functions/operators
transaction semantics
isolation/locking
extensions
backup/restore
monitoring
operational commands一个应用只用简单 SELECT/INSERT,兼容度可能足够;一个应用依赖 PostGIS、
自定义 operator class、logical decoding、advisory lock、trigger、COPY、
RLS 和精细 catalog 查询,迁移面完全不同。
不要用厂商兼容百分比替代自己的 feature inventory。
专用分析系统
专用 OLAP 系统通常优化:
columnar compression
large scans
vectorized execution
distributed aggregation
high analytical concurrency
object storage / tiering它可能显著优于 PostgreSQL 处理某类宽表聚合,但会引入第二套:
ingestion / CDC
schema mapping
data freshness
deduplication
late-event handling
access control
backup/recovery
monitoring/on-call
cost model
query semantics如果 OLTP truth 仍在 PostgreSQL,必须定义两个系统不一致时谁是事实来源。
候选能力矩阵
以下不是产品评分,而是评审问题:
| 维度 | 单机/副本 | FDW | Citus 类扩展 | 兼容分布式库 | 专用 OLAP |
|---|---|---|---|---|---|
| 原生 PG 语义 | 最高 | 本地/远端 PG | 高但分片有边界 | 必须实测 | 通常较低 |
| 单租户局部性 | 原生 | 手工路由 | 分布键核心 | 依实现 | 依模型 |
| 全局聚合 | 单节点 | 可下推/合并 | 分布式 partial/final | 依实现 | 核心场景 |
| 跨分片事务 | 不适用 | 有明显限制 | 需按版本/形状验证 | 需验证 | 通常非 OLTP 重点 |
| 扩展生态 | 原生 | 两端一致性 | 需验证组合 | 通常有限 | 不适用/自有 |
| 运维体系 | 已有 | 多 PG + 编排 | coordinator/workers | 新体系 | 第二套体系 |
| 新鲜度 | 即时/复制 lag | 远端即时视连接 | 即时视事务 | 依实现 | CDC/批次 lag |
| 退出成本 | 低 | 中 | 中高 | 高 | 高 |
矩阵中的每个“需验证”都要变成 PoC 用例。
所有权边界
候选不仅有技术 owner:
| 责任 | 必须有人承担 |
|---|---|
| schema 与分布键 | 数据模型 owner |
| query migration | 应用 owner |
| ingestion/CDC | 数据平台 owner |
| cluster lifecycle | DBA/SRE |
| correctness reconciliation | 业务 owner + 数据 owner |
| incident decision | on-call |
| cost | 预算 owner |
| exit | 项目 sponsor |
缺少 owner 的候选不能因为跑分快进入生产。
17.4.2 SQL 兼容不等于事务、扩展和运维兼容
建立兼容性分层
推荐至少分八层:
L1 protocol
L2 syntax
L3 type and expression semantics
L4 transaction and concurrency
L5 schema objects and extensions
L6 planner/performance behavior
L7 operations and observability
L8 failure/recovery and lifecycle只有 L1/L2 通过,应用仍可能在 L3–L8 失败。
协议兼容
验证:
- TLS、SCRAM、GSS/SSO;
- connection parameters;
- prepared statements;
- binary/text format;
- COPY;
- cancellation;
- notices/errors 与 SQLSTATE;
- connection pool transaction/session mode;
- driver features;
- failover reconnect。
能用 psql 登录只是起点。
SQL 与类型语义
测试应用真实使用的:
numeric precision and rounding
timestamp/time zone
collation and locale
NULL ordering
JSON/JSONB
arrays/ranges/multiranges
generated columns
identity/sequence
UPSERT/MERGE/RETURNING
CTE/window/lateral
recursive query同样语法若类型、collation 或时区不同,会返回不同结果。
postgres_fdw 官方文档也建议 foreign table 的类型和 collation 与远端精确
匹配,否则本地与远端对条件的解释可能不同。它还不会自动导入除 NOT NULL
之外的约束,因为错误约束可能导致规划器做出不安全推断。
事务与并发语义
需要独立验证:
READ COMMITTED snapshot
REPEATABLE READ
SERIALIZABLE
row/table/advisory locks
deadlock detection
savepoints
DDL transactionality
cross-shard transaction
retry error classes
sequence behavior例如“支持 serializable”不够,要验证:
- 冲突时 SQLSTATE;
- 是否需要 client retry;
- 多分片是否同样保证;
- range/predicate conflict 如何实现;
- failover 后 in-flight transaction 的结果;
- unknown commit 如何对账。
schema 与扩展兼容
列清单:
SELECT
extname,
extversion
FROM pg_catalog.pg_extension
ORDER BY extname;对每个扩展检查:
- 是否可安装;
- exact version;
- trusted/non-trusted;
- shared preload;
- 类型、函数、operator、index AM;
- logical/physical replication;
- backup/restore;
- rolling upgrade;
- 每个节点一致性。
不能把“兼容 PostgreSQL”理解为兼容任意 PostgreSQL 扩展。
catalog 兼容
许多工具读取:
pg_catalog
information_schema
pg_stat_*
pg_locks
pg_settings
pg_extension
pg_class/pg_attribute/pg_index候选可能接受这些查询但字段为空、语义不同或只反映 coordinator。验证:
- migration tool;
- ORM introspection;
- monitoring exporter;
- backup tool;
- schema diff;
- incident runbook;
- 自定义运维脚本。
planner 兼容
相同 SQL 的计划可以完全不同。需要观察:
where execution happens
which shards are pruned
which filters/joins/aggregates push down
how many rows cross network
how coordinator merges
what spills
what happens under skew本章同一个 FDW 月报有两种 SQL:
parent aggregate:
fetch 240,000 facts
aggregate locally
explicit per-shard daily aggregate:
fetch 480 + 480 aggregate rows
aggregate monthly locally语义相同,执行位置不同。兼容性测试不能只检查最终 rows。
运维兼容
对比日常动作:
| 动作 | 问题 |
|---|---|
| provision | 声明、包、密钥、节点身份如何? |
| scale | 加节点是否自动,旧数据如何移动? |
| backup | 一致点、加密、保留、校验如何? |
| restore | 空环境恢复、route metadata 如何? |
| failover | coordinator/worker 谁仲裁? |
| upgrade | rolling、停机、扩展顺序? |
| schema change | fan-out、失败补偿? |
| observability | 全局与每 shard 指标? |
| security | HBA、证书、user mapping、secret? |
| decommission | 数据擦除与证明? |
工具名字相同也不表示语义相同。例如在 coordinator 执行 VACUUM 是否覆盖
所有 shard,要由目标产品和版本证明。
错误兼容
应用通常围绕 SQLSTATE 决定:
retry
abort
return conflict
mark dependency unavailable候选必须保留或重新映射这些错误语义。测试:
- unique violation;
- serialization failure;
- deadlock;
- lock timeout;
- statement timeout;
- connection failure;
- read-only transaction;
- insufficient privilege;
- disk/full or quota;
- shard unavailable。
只测试成功路径会让第一场故障变成兼容性测试。
精度与顺序
分析结果的隐性差异:
floating aggregate order
approximate distinct
collation sort
NULL order
time zone database version
decimal scale
non-deterministic top-N ties冻结输出应:
- 使用 exact numeric 或定义误差;
- 明确
ORDER BY与 tie-breaker; - 固定时区/locale;
- 记录 approximate 算法/version/seed;
- 对 checksum 使用稳定序列化。
17.4.3 用同一工作负载和失败条件比较
先冻结语义
比较协议应先固定:
schema
data generator / snapshot
business queries
expected results
freshness point
concurrency schedule
failure schedule
versions/config
measurement method本章:
fixture = ch17-analytics-v1
frozen_at = 2026-07-29T00:00:00Z
monthly rows = 32
monthly checksum = 644d45544ebbc2a80c42270c38ac6885任何候选先生成同一月报,再谈性能。
workload suite
至少包含:
高选择性单租户读
WHERE tenant_id = 3 AND occurred_on >= DATE '2026-04-01'验证 pruning、index、route、read amplification。
全局可分解聚合
count/sum 按租户和月份,验证 partial/final 与传输。
同分片 JOIN
account + sales,验证真实 join pushdown。
非分布键 JOIN
故意触发 shuffle 或拒绝,量化代价。
小写入与幂等重试
验证事务、unique、retry。
批量装载
验证 ingest、WAL/replication、rebalance。
schema change
增列、建索引、backfill,验证 mixed-version。
backup/restore
从空环境恢复并跑 checksum。
数据规模阶梯
不要只跑一个尺寸:
S: fits in memory
M: working set near memory
L: exceeds memory
XL: near storage/maintenance target观察曲线和拐点,而不是挑一张最好看的柱状图。
冷暖缓存
至少区分:
warm repeated query
cold/evicted data
after restart
after rebalance
after restore
after schema/index build专用分析系统和 PostgreSQL 对缓存、编译、数据格式转换的预热不同。只比较 第十次执行或只比较第一次执行都可能偏颇。
并发与到达模型
开放环和封闭环会得出不同结论:
closed-loop:
client waits for response, then sends next
overloaded system self-throttles
open-loop:
requests arrive by schedule independent of completion
queueing and overload become visible生产若有固定到达率,基准不能只用少量客户端闭环。还要记录 client queue 与 server queue,避免 coordinated omission。
资源和成本同报
每个结果同时报告:
latency distribution
throughput
error rate
CPU seconds
memory peak
storage read/write
temp/spill
network bytes
WAL/replication
storage footprint
node count
operator time
license/cloud cost“P95 快 2 倍但使用 8 倍节点”与“同成本快 2 倍”不是同一结论。
失败矩阵
对每个候选执行:
| 故障 | 验证 |
|---|---|
| query cancel | 远端工作是否停止、资源是否释放 |
| worker/shard down | 单分片与全局查询如何返回 |
| coordinator down | 新连接、已有事务、恢复 |
| network partition | timeout、unknown commit、重试 |
| disk pressure | backpressure 与告警 |
| replica lag | freshness 标识与路由 |
| rebalance interrupted | resume、重复/遗漏 |
| schema node drift | 拒绝、修复与可见性 |
| backup during load | 恢复一致性 |
失败结果必须是验收的一部分,不是“以后做 chaos”。
本章的最小失败条件
冻结 PoC 至少证明:
application write -> SQLSTATE 42501
shard B unreachable -> global query SQLSTATE 08001
shard B unreachable -> tenant 2 scoped read = 30000
server catalog after rollback = before failure它没有证明:
- 真实网络分区;
- process kill;
- WAL/replica behavior;
- coordinator HA;
- shard failover;
- in-flight distributed write;
- rebalance resume。
这些是生产 PoC 的追加用例。
benchmark result template
每条结论写成:
claim:
two-stage aggregation reduces coordinator input
environment:
PostgreSQL 18.4, postgres_fdw 1.2
same-host/same-instance loopback
input:
ch17-analytics-v1, 240,000 facts
evidence:
naive Append actual rows=240000
two-stage Append actual rows=960
both byte-identical to frozen monthly CSV
scope:
row-transfer shape only
not proven:
network bytes, latency, throughput, HA, scaling这个模板迫使作者把结论和外推边界放在一起。
评分前设置 veto
某些条件不应靠加权平均掩盖:
incorrect result
cannot meet RPO/RTO
unsupported mandatory extension
unacceptable data residency
no recoverable backup
license conflict
no exit path
unknown-commit without business reconciliation任何 veto 失败,候选退出;不能用“查询快 30%”抵消。
决策表
通过 veto 后再评分:
| 维度 | 权重 | 证据 | 分数 | 不确定性 |
|---|---|---|---|---|
| correctness | veto | golden/checksum | pass | low |
| workload SLO | 25 | representative replay | ||
| failure/RPO/RTO | 20 | drills | ||
| operability | 15 | day-2 tasks | ||
| compatibility | 15 | feature inventory | ||
| cost | 10 | same horizon/TCO | ||
| migration | 10 | rehearsal | ||
| exit | 5 | reverse rehearsal |
“不确定性”单列,避免没有验证的候选因为乐观估分胜出。
本节结论
比较方法的输出不是产品排行榜,而是:
baseline
candidate contract
evidence bundle
known limitations
veto results
cost/ownership
migration and exit
decision trigger下一节构造一个最小 FDW PoC,目的不是给候选打性能分,而是验证“租户路由、 远端聚合、权限和部分失败能否被证据化”这一个关键假设集合。
上一节:何时需要分布式 · 返回本章目录 · 下一节:部署最小分布式 PoC · 查看全书目录 · 查看索引中心