# 内核、发行版与托管服务

LLMS 索引： [llms.txt](/llms.txt)

---

“基于 PostgreSQL”可能表示使用上游源码加少量补丁，也可能只表示接受一部分
PostgreSQL wire protocol。两者对扩展的意义完全不同。

选扩展前先冻结运行载体：

```text
server implementation
  + server major/minor/build
  + OS/distribution/architecture
  + package source and build
  + topology and managed restrictions
  + database extension object version
```

扩展不是脱离这些条件存在的功能标签。

## 14.2.1 上游 PostgreSQL、补丁内核与兼容性承诺 {#item-14-2-1}

### “内核”至少要说明源码与构建

在本书中，上游 PostgreSQL 指 PostgreSQL Global Development Group 发布的
代码与版本语义。供应者可以在其上：

- 回移安全或缺陷补丁；
- 增加认证、存储、优化器或复制能力；
- 替换某些系统组件；
- 发布自己的包名、构建号与支持周期；
- 形成需要独立升级路径的 fork。

“补丁少”不自动等于二进制兼容；“版本号相同”也不证明动态库来自相同 ABI
与编译选项。C 扩展会与 server headers、符号、内存上下文、catalog 和内部
API 交互。PostgreSQL 不承诺跨 major 的内部 C ABI，扩展通常必须按目标
major 构建。

先采原始身份：

```sql
SELECT version();
SHOW server_version;
SHOW server_version_num;

SELECT
    name,
    setting,
    source
FROM pg_settings
WHERE name IN (
    'server_version',
    'server_version_num',
    'data_directory',
    'config_file',
    'shared_preload_libraries'
);
```

再采主机/包事实：

```bash
postgres --version
pg_config --version
pg_config --configure
uname -m
```

在 Pigsty 环境还要记录 `pg_version`、`pg_mode`、镜像/仓库快照与节点实际包
清单。不要只复制应用连接返回的 `version()`；代理、兼容层或读写路由可能让
它不足以唯一标识整个集群。

### 扩展兼容承诺要逐项问

对一个补丁内核或 fork，至少问：

| 问题 | 为什么影响扩展 |
|---|---|
| 是否使用上游系统目录布局 | 扩展 SQL 可能查询/修改 catalog |
| 是否支持 PGXS 与上游 server headers | 决定能否按目标内核构建 |
| 是否保持所需 C symbols/hook | 决定动态库能否加载和正确运行 |
| WAL、存储和复制是否改动 | 自定义类型/访问方法能否在备库恢复 |
| `pg_upgrade` 是否使用上游路径 | 外部模块与数据格式怎样迁移 |
| 由谁发布扩展包 | 上游扩展 release 不等于目标内核构建 |
| 谁承担联合支持 | 内核供应者和扩展供应者是否互相认可组合 |

“这个扩展支持 PostgreSQL 18”只说明扩展项目的一个范围；目标若是
PostgreSQL 18 衍生内核，仍需该组合的构建与验证证据。

### SQL 扩展也不必然可移植

没有 C 动态库只能降低 ABI 风险，不能消除语义耦合。纯 SQL 扩展可能依赖：

- 特定系统目录列；
- 特定函数、数据类型或语法版本；
- planner 行为；
- event trigger；
- trusted extension 机制；
- superuser/owner 权限；
- 复制、dump 或安全策略。

因此兼容性不是“C 扩展危险、SQL 扩展安全”的二分，而是依赖面的大小。

### 支持矩阵要精确到组合

不要写：

```text
supports PostgreSQL
```

而写：

```text
server: upstream PostgreSQL 18.6, vendor build X
OS: Ubuntu 24.04 amd64
extension package: pgvector build Y
database object: vector 0.8.4
topology: 1 primary + 2 physical standbys
preload: not required
backup/restore: rehearsed on clean target Z
```

同一扩展在 EL9/aarch64、Ubuntu/amd64 和某托管服务上是三个验证组合。

## 14.2.2 包仓库、容器镜像与托管白名单 {#item-14-2-2}

### 包仓库解决供应，不替你做数据库升级

发行版包通常编码：

```text
extension project version
PostgreSQL major
OS family/version
CPU architecture
vendor release/build
```

例如 Pigsty 的包别名 `pgvector` 可以映射到不同系统上的：

```text
EL:     pgvector_18*
Debian: postgresql-18-pgvector
```

这层映射很有价值，但别名不是 SQL 名：

```yaml
pg_extensions: [pgvector]   # package intent
```

数据库中仍是：

```sql
CREATE EXTENSION vector;    -- SQL extension name
```

仓库有包只证明“某个源声明可以供应”；还要验证：

- 目标 OS/PG major/架构是否有具体 artifact；
- repo metadata、签名与校验是否可信；
- 包是否已经同步到本地/离线仓库；
- 所有节点安装的 build 是否相同；
- control、更新 SQL 和动态库是否都随包出现；
- 升级包后每个数据库的 `extversion` 是否仍需迁移。

锁定生产变更时，保存具体包 NEVRA/DEB version 或文件哈希，不只保存一个
会随仓库漂移的“latest”别名。

### 容器把供应快照化，但不把数据生命周期一起快照

容器镜像可以把 server 与扩展文件打包在同一 digest 中：

```text
image digest
  ├─ postgres binary
  ├─ control and SQL scripts
  └─ shared libraries
```

这有助于节点一致性，却有几个陷阱：

1. 数据目录通常在持久卷，里面的 `pg_extension.extversion` 不随镜像自动
   更新；
2. 滚动换镜像期间，新旧 pod 可能同时服务，动态库 build 必须满足复制和
   failover 条件；
3. 恢复 job、备份验证 job 和临时维护容器也需要相同扩展文件；
4. 镜像能启动不代表 `ALTER EXTENSION UPDATE` 已完成；
5. 使用浮动 tag 会把可复现优势重新丢掉。

因此镜像 digest 是供应锁，不是数据库迁移状态。

### 托管白名单是产品合同

托管 PostgreSQL 常限制超级用户、文件系统和 server 参数。用户通常只能从
服务商允许列表中执行：

```sql
CREATE EXTENSION approved_name;
```

这带来不同问题：

- 是否允许该扩展；
- 允许哪个对象版本；
- 哪些区域、实例规格或 PG major 可用；
- 是否需要服务商参数组/重启；
- 谁控制更新窗口；
- 是否暴露扩展 owner；
- 是否允许自定义 schema；
- 备份、只读副本、跨区恢复与 major upgrade 是否支持；
- 从服务迁出时怎样导出自定义类型数据。

托管服务显示“支持 pgvector”，仍不能直接套用自建包的版本、参数和升级
步骤。白名单名称相同，控制面合同可能不同。

### 仓库、镜像与白名单的共同锁文件

为每个环境维护：

```yaml
server:
  implementation: upstream-postgresql
  version: 18.6
  build: vendor-build-id
  os: ubuntu-24.04-amd64

extension:
  sql_name: vector
  project: pgvector
  package_alias: pgvector
  package_version: exact-build
  object_version: 0.8.4
  preload: false

supply:
  repo_snapshot_or_image_digest: immutable-id
  control_sha256: ...
  install_sql_sha256: ...
  library_sha256: ...

validation:
  primary: passed
  standbys: passed
  clean_restore: passed
  major_upgrade_clone: passed
```

不是所有项目都要手写 YAML，但这些字段必须能从 CMDB、inventory、镜像
SBOM、evidence 或变更单还原。

## 14.2.3 “兼容 PostgreSQL”需要逐层验证 {#item-14-2-3}

### 五层兼容模型

把“兼容”拆为五层：

| 层 | 要验证什么 | 典型误判 |
|---|---|---|
| SQL 语义 | 类型、函数、事务、隔离、DDL 行为 | 能跑简单 CRUD 就等于 PostgreSQL |
| Wire protocol | 驱动连接、认证、参数、错误字段 | 驱动能连就等于 server 等价 |
| Catalog/API | `pg_catalog`、扩展机制、统计视图 | ORM 能用就等于管理工具能用 |
| Extension | control/SQL/C ABI、preload、成员与版本 | “支持 pgvector”就等于任意版本 |
| Operations | 备份、PITR、复制、failover、upgrade、监控 | 单实例功能测试代替生产生命周期 |

兼容声明必须说明通过了哪层。一个 wire-compatible 服务可能不提供
`CREATE EXTENSION`；一个支持扩展 SQL 接口的服务可能不允许用户控制版本；
一个上游二进制兼容内核仍可能在备份或升级控制面上有不同合同。

### 用需求驱动 probe

不要为了“全面”跑一堆无关 SQL。根据应用依赖形成最小 probe：

```text
application contract
  ├─ exact type/function/operator signatures
  ├─ SQLSTATE and transaction behavior
  ├─ planner/index behavior
  ├─ privilege boundary
  ├─ backup/restore representation
  └─ failover/upgrade behavior
```

本章对 `pg_trgm`/`vector` 的 probe 包括：

```sql
-- 供应可见性
SELECT * FROM pg_available_extension_versions
WHERE name IN ('pg_trgm', 'vector');

-- 数据库对象
SELECT * FROM pg_extension
WHERE extname IN ('pg_trgm', 'vector');

-- 成员关系
SELECT ... FROM pg_depend WHERE deptype = 'e';

-- 索引实现
SELECT ... FROM pg_index JOIN pg_am JOIN pg_opclass ...;

-- 权限失败
ALTER EXTENSION pg_trgm UPDATE TO '1.6'; -- application: 42501

-- 行为与计划
EXPLAIN ... title % 'PostgreSQL extenson';
EXPLAIN ... ORDER BY embedding <-> '[1,0,0]';
```

这些 probe 仍没有覆盖备库与恢复，所以 evidence 不能写“生产兼容已验证”。

### 区分等价、适配与迁移

三个词不要混用：

- **等价**：在声明范围内行为相同；
- **适配**：应用通过条件分支、兼容层或限制使用范围后可运行；
- **迁移**：接受行为变化并修改 schema、查询、运维或 SLO。

例如目标不支持 HNSW，但支持精确向量距离：

```text
不是：完全兼容 pgvector
可能是：类型/距离查询兼容，ANN 索引不兼容
决策是：小数据集适配，或迁移到另一检索架构
```

精确描述可以阻止“兼容”在采购、开发和事故处理中不断膨胀。

### 兼容矩阵

对候选平台填表：

| 验证项 | 上游自建 | Pigsty L1 | 托管候选 | 证据 |
|---|---:|---:|---:|---|
| SQL 扩展名/版本 |  |  |  | catalog |
| package/build |  |  | 服务商托管 | package/API |
| preload/restart |  |  |  | live setting |
| owner/权限 |  |  |  | negative test |
| GIN/HNSW |  |  |  | catalog + plan |
| 物理副本 |  |  |  | failover test |
| schema-only dump |  |  |  | dump artifact |
| clean restore |  |  |  | restore report |
| major upgrade |  |  |  | cloned rehearsal |
| portable export |  |  |  | row/checksum |

空格不是“默认通过”，而是未验证。若某项与业务无关，可以标 `N/A` 并说明
理由；不能把它悄悄留空后宣称全兼容。

### 停止线

遇到以下任一情况，不进入生产：

- 无法唯一标识 server/扩展 build；
- 主备节点供应状态不一致；
- 只有创建成功，没有 clean restore；
- 目标服务商不能说明 major upgrade 时怎样处理扩展；
- 自定义类型无法导出为稳定交换格式；
- 兼容层不返回应用依赖的 SQLSTATE/事务语义；
- 供应者与扩展项目相互否认联合支持；
- 只能使用浮动包/tag，无法复现已测组合。

### 本节结论

“PostgreSQL 兼容”不是布尔值，而是一个带版本、层次和证据的向量：

```text
compatibility =
  SQL × protocol × catalog × extension × operations
  under exact version/build/topology constraints
```

扩展越深入类型、索引、hook 与存储，越不能只验证前两层。

---

[上一节：PostgreSQL 扩展机制](../01/) · [返回本章目录](../) · [下一节：扩展选型的六个问题](../03/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
