Hindsight 0.7.1 Postgres 升级风险与方案 C 规划
- HTML: https://decision.ht1072.top/2026-06-01-hindsight-071-postgres-migration-risk.html
- Local HTML:
[已移除本地路径] - Generated: 2026-06-01T18:32:45+08:00
Hindsight 0.7.1 Postgres 升级风险与处理规划
页面摘要区
结论: Hindsight 0.7.x 的方向是对的,它解决了 memory_links 中 entity 类型边 O(N²) 膨胀的问题;但当前 v0.7.1 官方包在本机 0.6.2 → 0.7.1 Postgres 升级路径上存在 migration 硬阻塞,不建议直接升级 live。
核心风险: 官方 migration 中多处 DROP/CREATE INDEX CONCURRENTLY 会在 Alembic/SQLAlchemy 事务块内执行,Postgres 报错 cannot run inside a transaction block;同时 hindsight-api-slim 依赖里只有 psycopg2-binary,实际迁移路径还需要 psycopg。
推荐策略: 暂不动 live 0.6.2;先向上游提交 issue;如果要推进方案 C,应做 patched 0.7.1 + cloned DB rehearsal + clone-and-swap cutover,而不是 in-place 直接升。
行动清单: 1)保留本次审计目录;2)发布本决策记录到 wiki/HTML;3)向 vectorize-io/hindsight 提 issue;4)等待官方修复或准备可审计 production patch;5)fresh dump 重跑 rehearsal 后再讨论生产维护窗口。
风险边界: rehearsal 中为了验证 runtime,曾在 isolated venv + copied DB 中把 CONCURRENTLY 改成普通 DDL,这不能直接作为 production 方案;生产要么使用真正的 Alembic autocommit,要么拆出手工 pre-migration / batch cleanup。
1. 背景
本机当前 live Hindsight:
API: 127.0.0.1:8889
Version: 0.6.2
Status: healthy
Database: pg0/PostgreSQL 18.1 on 127.0.0.1:5432
本次任务是评估上游 0.7.1 是否值得升级,以及是否能安全从本机 live 0.6.2 迁移过去。
隔离演练路径:
isolated venv: [已移除本地路径]
isolated API: 127.0.0.1:18889
rehearsal DB: hindsight_071_rehearsal_20260601_151948
审计目录: [已移除本地路径]
live 8889 和 live DB 未直接修改。
2. 0.7.x 解决的问题
上游 issue #1887 指出,0.6.x 中 memory_links 的 link_type = 'entity' 行会按高频实体近似 O(N²) 增长,导致表膨胀、dead tuples、stats 慢查询、CPU 飙高和连接池耗尽。
官方在该 issue 中说明,0.7.0 已重新设计:
- entity edges 不再物化为
memory_links行; - entity relationships 改为从
unit_entities按需派生; - migration
e9b2c7d1f3a4_drop_entity_memory_links会删除既有entitylinks。
本机 rehearsal DB 迁移前后验证:
迁移前 memory_links:
semantic | 53180
entity | 39372
temporal | 38768
caused_by| 981
迁移后 memory_links:
semantic | 53200
temporal | 38788
caused_by| 981
说明 0.7.x 的方向和目标是有效的。
3. 本机实测阻塞点
3.1 缺少 psycopg
hindsight-api-slim 0.7.1 安装后包含:
psycopg2-binary==2.9.12
但启动 migration 时 SQLAlchemy 使用 postgresql+psycopg 路径,报:
ModuleNotFoundError: No module named 'psycopg'
补救方式:
uv pip install --python [已移除本地路径] 'psycopg[binary]'
3.2 CONCURRENTLY 在 transaction block 中执行
补 psycopg 后,migration 继续失败:
DROP INDEX CONCURRENTLY cannot run inside a transaction block
已撞到的 revision:
e1b2c3d4f5a6_drop_unused_indexes.py
e9b2c7d1f3a4_drop_entity_memory_links.py
继续扫描上游 v0.7.1/main 发现同类写法还存在于多个 migration:
a2b3c4d5e6f8_add_gin_index_source_memory_ids.py
b3c4d5e6f7g8_add_temporal_date_indexes.py
c1a2b3d4e5f6_enable_pg_trgm_and_entities_trgm_index.py
d2e3f4a5b6c7_add_memory_links_expansion_indexes.py
d4e5f6g7h8i9_gin_source_memory_ids_fastupdate_off.py
e1b2c3d4f5a6_drop_unused_indexes.py
e9b2c7d1f3a4_drop_entity_memory_links.py
上游 main 与 v0.7.1 的相关 migration 文件对比结果为 SAME,说明截至本次检查时,上游 main 尚未修复该问题。
4. 隔离验证结果
为了验证 0.7.1 runtime 本身是否可用,本次只在 isolated venv + copied rehearsal DB 中做 rehearsal-only patch:
将 CONCURRENTLY 改成普通 DDL
移除 migration 中手写 COMMIT
这不是 production 方案,只用于确认 runtime 能力。
补丁后 isolated 0.7.1 启动成功:
{"status":"healthy","database":"connected"}
{"api_version":"0.7.1"}
验证通过:
banks ✅
stats ✅
manual retain ✅
manual recall ✅
consolidation ✅
operations clean ✅
关键结果:
alembic_version: b5a4c3e2f1d8
pending_operations: 0
failed_operations: 0
pending_consolidation: 0
failed_consolidation: 0
5. 对 live 的影响
短期:本机 live 仍健康,当前 rehearsal DB 规模较小,不是马上要抢修。
DB size: 104 MB
memory_links: 39 MB
entity links: 39372
中长期:继续停留在 0.6.2 会保留 entity links 膨胀风险。如果后续 retain、历史回放、consolidation 增加,memory_links 表可能持续膨胀。
直接升级的风险更高:如果直接在 live DB 上跑官方 0.7.1 migration,可能出现 API 启动失败、alembic_version 半路状态、索引部分删除、DB schema 中间态等问题,回滚不能只退 Python 包,可能需要恢复 dump。
6. 方案 C:patched 0.7.1 的规划
6.1 原则
不做 in-place 硬升。采用:
patched 0.7.1 + cloned DB rehearsal + clone-and-swap cutover
6.2 Patch 范围
只修 migration/依赖,不改业务逻辑。
- 补依赖:
psycopg[binary]>=3.3.0
- 修
CONCURRENTLYmigration:
将:
op.execute("COMMIT")
op.execute("DROP INDEX CONCURRENTLY IF EXISTS ...")
改为:
with op.get_context().autocommit_block():
op.execute("DROP INDEX CONCURRENTLY IF EXISTS ...")
- 单独处理
e9b2c7d1f3a4的 entity cleanup。
生产更稳的方式是将大规模 entity links 删除拆成可观测 batch cleanup:
DELETE FROM memory_links
WHERE ctid IN (
SELECT ctid
FROM memory_links
WHERE link_type = 'entity'
LIMIT 50000
);
循环直到 0 行,并在结束后:
VACUUM ANALYZE memory_links;
6.3 Rehearsal 要求
fresh dump 新建 rehearsal DB,必须验证:
health/version/banks/stats
manual retain/manual recall
consolidation operation completed
alembic_version == head
entity links cleared
pending_operations = 0
failed_operations = 0
还要记录:
migration 耗时
entity cleanup 耗时
DB size 前后变化
memory_links dead tuples / vacuum 后状态
索引列表
6.4 Cutover 策略
生产采用 clone-and-swap:
- 维护窗口开始,停止 Hindsight API 写入;
- final dump live DB;
- 恢复到新 DB,如
hindsight_071_prod_candidate_<timestamp>; - patched 0.7.1 指向 candidate DB 跑 migration;
- isolated API 验证通过;
- systemd/env 切换到 patched venv + candidate DB;
- live
8889验证通过; - 保留旧
0.6.2venv、旧 DB、旧 env 和 final dump 作为回滚点。
6.5 回滚
不依赖 downgrade migration,直接切回旧 venv + 旧 DB:
stop hindsight-api
restore env/systemd to 0.6.2 + old DB
start hindsight-api
verify health/version/stats/recall
7. 建议
当前建议:
不直接升级 live。
先向上游提交 issue。
等待官方修复,或准备可审计 production patch 后 fresh rehearsal。
如果后续继续推进方案 C,应先把 patch 做成可重复脚本/本地分支,并至少完成两次 fresh rehearsal,再安排生产维护窗口。
8. 证据与路径
本机审计目录:
[已移除本地路径]
关键文件:
verify-banks.json
verify-retain.json
verify-recall-after.json
verify-consolidate-operation.json
verify-stats-final.json
*.noconcurrent.diff
hindsight-071-api-18889-*.log
venv-freeze-hindsight-ish.txt
uv-install-psycopg.txt
上游相关:
Repo: https://github.com/vectorize-io/hindsight
Issue #1887: Entity links grow O(N²) per shared entity...
Issue #1902: PostgreSQL upgrade to v0.7.1 fails: missing psycopg and CONCURRENTLY migrations run inside transaction blocks
Release: v0.7.1, 2026-05-28
本次已提交的上游 issue:
https://github.com/vectorize-io/hindsight/issues/1902
9. 当前执行状态
本记录生成时间:2026-06-01 18:31:18 CST。
本记录用于 wiki / HTML / Hindsight retain pointer 归档,并作为向上游提 issue 的依据。