15.6 扩展部署与运行代价
到目前为止,我们只证明了检索行为。生产采用还要回答:
本节把 PostgreSQL 机制映射到 Pigsty 4.5,但仍以 live 节点、系统目录和实际 证据为准。
15.6.1 安装检索扩展并核对版本
复用第 14 章的三层状态
检索扩展仍然有三层:
pg_trgm 随 PostgreSQL contrib 交付;vector 的项目/包常叫 pgvector,而
SQL 扩展名是 vector。不要混写:
本章不会安装或升级它们,而是要求第 14 章最终状态:
如果版本、owner、schema 或 marker 不符,context.sql 拒绝。下游实验不能
悄悄接管上游扩展。
Pigsty 中分开“装包”和“启用”
Pigsty 4.5 当前文档指出:
pgvector随pgsql-main默认安装;pg_trgm位于默认启用扩展列表;- 可通过
pg_packages/pg_extensions影响包; - 可通过
pg_default_extensions影响数据库默认启用对象。
本章给出的
pigsty-declaration.example.yml
只是合并片段:
实际版本中 pgvector 可能已被 pgsql-main 包别名覆盖,重复声明是否允许、
包名如何展开、目标 OS/PG major 是否有构建,都要用目标 inventory 与
Pigsty 文档确认。
教学夹具把扩展放在 shop_ch14,是为了凸显 namespace/owner。生产片段使用
public 只是示例,不是推荐所有扩展都堆进 public。schema 选择必须同时
满足:
- extension 是否 relocatable/是否强制 schema;
- 应用是否用全限定名称;
search_path安全;- dump/restore;
- 运维与升级脚本;
- 权限最小化。
L1 每个节点都要核对
物理复制会把数据库对象复制到备库,但不会把 OS 软件包和动态库通过 WAL
复制过去。主库 CREATE EXTENSION vector 成功,某备库仍可能因缺
vector.so 在查询、恢复或升主后失败。
对每个 L1 host 收集:
再核对目标 major 的 package manager 版本与文件 hash。不能从当前 shell
PATH 里的 pg_config 猜正在运行的 server;先从实例确认 server major,
再找对应安装树。
数据库内:
控制文件可见性:
两份目录回答不同问题:
pg_available_extension_versions:server 支持文件允许哪些版本;pg_extension:当前 database 创建了哪个对象版本。
安装权限不要交给应用
本章角色边界:
pg36_app 对 product_search UPDATE 必须返回:
真实商品服务当然需要写入,但写角色不等于在线读角色必须拥有表级任意 UPDATE。 可使用:
- 受控迁移角色;
- 列级权限;
- 参数化函数;
- 独立异步 embedding worker;
- 队列/作业表状态机。
尤其不要让业务请求角色创建、升级或删除扩展。
证据边界
本章正式运行:
所以 manifest 明确:
移植到 Pigsty 后要补:
15.6.2 观察索引体积、构建、查询和维护
先列出四类物理对象
本章商品表有:
基础盘点:
17 行夹具看到的 8/16/32 KiB 级数字主要由最小页分配决定,不能计算
“每百万商品多少 GiB”。size-catalog.csv 只是证明对象存在且非零。
生产 size baseline 应记录:
否则两个 size 数字不可比较。
构建要观察过程与阻塞
初始离线载入通常:
比逐行维护索引高效。在线已有表则通常考虑:
它减少对写入的阻塞,却有更长构建时间、额外扫描、资源占用和失败状态。运行时 观察:
并结合:
发布后必须确认 pg_index.indisvalid/indisready/indislive,不能只看 DDL
client exit。
查询观测分机械与用户两层
机械层:
看:
- index/seq/bitmap path;
- actual rows 与估算;
- filter removed rows;
- buffers 与 temp I/O;
- planning/execution time;
- 生效的非默认 settings。
用户层:
执行快但 recall 差,不是成功;quality 高但 P99 超时,也不是成功。
Pigsty 默认启用/预加载的 pg_stat_statements 可帮助聚合 SQL 调用与耗时,
但要为检索 query 保持可归一的 SQL 形状,并将业务 query id/segment 放在
受控日志或 trace,而不是拼进 SQL 注释造成 statement 指纹爆炸。
写入成本要单独压测
文本变化会更新两个 GIN 和 generated tsvector;向量变化会更新 HNSW。
测:
可以在受控事务前后比较:
再用 pg_wal_lsn_diff 估算该受控批次产生的 WAL。并发生产环境还有其他
事务,不能把全局 LSN 差未经隔离就归给一个作业。
HNSW 维护不是普通 B-tree 的复制粘贴
pgvector 官方说明 HNSW vacuum 可能耗时,并给出先 REINDEX INDEX CONCURRENTLY 再 VACUUM 的一种加速建议。这是需要谨慎评估的维护动作,
不是每晚固定模板:
- reindex 需要额外磁盘与构建资源;
- concurrently 有更长窗口和失败恢复;
- vacuum 仍要处理 heap;
- 副本会重放相关 WAL;
- 索引重建期间 recall/latency 要观测;
- 新 index 的参数与 opclass 必须一致。
先在代表性副本/演练环境测周期,再决定维护阈值。
监控矩阵
| 维度 | PostgreSQL 证据 | Pigsty/平台视图 |
|---|---|---|
| SQL 调用/耗时 | pg_stat_statements、logs |
dashboard/alerts |
| 执行计划 | EXPLAIN、auto_explain |
集中日志 |
| index 使用 | pg_stat_user_indexes |
表/索引面板 |
| 表生命周期 | pg_stat_user_tables |
vacuum/bloat 面板 |
| 构建进度 | pg_stat_progress_create_index |
变更任务证据 |
| WAL/副本 | LSN、replication views | HA/replication 面板 |
| 主机资源 | PostgreSQL/OS stats | node/PG exporter |
| 质量/ANN recall | 自建 eval job | release/SLO dashboard |
最后一行不能由通用数据库 exporter 自动推导。检索质量是业务测量,必须把 evaluation job 当成一等生产组件。
15.6.3 外部嵌入生成的权限、费用与数据边界
不要从数据库触发器同步调用外部 API
一个危险设计:
它把:
- 外部网络延迟;
- rate limit;
- provider outage;
- 费用;
- 密钥;
- 不确定重试;
放进数据库锁与事务寿命。远端已收费成功、本地事务却回滚时,还会出现不可 原子化的副作用。
更稳健的异步结构:
可用 outbox、作业表或消息系统实现;第 13 章已经讨论过触发器与异步边界。
幂等身份
一次 embedding 任务的自然 key 可以是:
写回时做 compare-and-set:
如果源文本在推理期间变化,旧结果不能覆盖新版本。重试同一 key 应复用已完成 结果或安全 upsert,避免重复收费。
worker 最小权限
embedding worker 通常需要:
- 读取允许外发的字段;
- 读取/更新自己的 job;
- 写特定 vector/model/status 列;
- 不需要 DDL、扩展 owner、超级用户;
- 不需要任意读其他敏感 schema。
API secret 放在 secret manager/受控运行环境,不存进 SQL、YAML 仓库、表 comment 或 evidence manifest。Pigsty 负责 PostgreSQL 平台,不意味着模型 密钥应注入数据库 server 进程。
若文本不能离开边界,可以:
- 在受控网络自托管模型;
- 只对批准字段生成;
- 做脱敏/分区处理;
- 或拒绝向量方案。
“先接 API,之后再补合规”不是试点策略。
费用模型
至少估算:
[ Cost = InitialBackfillTokens \times Price
- DailyChangedTokens \times Price
- QueryTokens \times Price
- RetryWaste
- Storage/Index/Compute ]
还包括:
- backfill 期间 API 并发与限流;
- 模型升级全量重算;
- 双版本存储与索引;
- 失败重试和重复调用;
- query embedding cache;
- 数据出口与网络;
- 本地推理 GPU/CPU 和运维。
费用控制要有:
缓存 query vector 时,key 必须包含 exact normalized text、model、template 与 版本;只按原始字符串缓存会在模型切换时串用旧空间。
数据生命周期要双向传播
删除或更正 source document 时,检查:
物理删除在 PostgreSQL 中还受 MVCC、vacuum、WAL 与备份保留影响。法律上的
删除承诺必须和备份/恢复政策一致,不能只执行一条 DELETE。
故障与降级
模型服务不可用时,搜索不一定要整体不可用:
每种 fallback 都要在离线标注集上测质量、在线压测容量,且不能放宽权限过滤。
上线前问题
- 哪些字段能外发,依据是什么?
- provider 是否保留输入/输出、是否用于训练?
- 模型版本是否可固定,变更如何通知?
- 单次、每日、回填、升级的费用上限是什么?
- 谁能读原文、调用服务、写 vector?
- 如何证明 vector 对应当前 source hash?
- 失败如何重试,何时进入 dead letter?
- 模型切换如何双写、评估、回退?
- 删除、备份与 provider 侧数据如何协调?
- 无模型服务时,业务还能提供什么质量的结果?
回答不了这些问题时,向量 PoC 可以继续离线,不能进入生产写链路。
上一节:混合检索与排序验证 · 返回本章目录 · 下一节:实战:pg36_shop 商品混合检索 PoC ·
查看全书目录 · 查看索引中心