Skip to content

[架构][RFC] 建议改为「PostgreSQL 为主库 + 衍生存储」的 System of Record 架构,根治跨库一致性问题 #893

Description

@Alex-Fleet

标题: [架构][RFC] 建议改为「PostgreSQL 为主库 + 衍生存储」的 System of Record 架构,根治跨库一致性问题

正文:

背景:当前设计的根因

当前代码把 PostgreSQL、Milvus、Neo4j、MinIO 当成平级的事务参与者,写入时试图对它们"同时原子提交":

根因不是"缺分布式事务",而是"设计上就不该有跨库事务"。PG / Milvus / Neo4j 是异构存储,2PC 等分布式事务不现实;靠补偿/对账只能缓解,无法根治。

目标架构:System of Record + Derived Stores

写入路径(唯一事务边界在 PG 内):
  业务操作
    ├─ 写 PostgreSQL(唯一权威源,事务内)
    └─ 写 outbox 事件表(同一事务,原子落盘)
         │
         ▼
  后台 worker 异步消费 outbox(best-effort + 重试 + 死信)
         ├─→ Milvus(向量索引:插入/删除)
         ├─→ Neo4j(图谱:MERGE/重建)
         └─→ MinIO(对象:幂等,按 key 隔离)

检索路径:
  Milvus / Neo4j 命中候选 → 回 PostgreSQL 校验存在性与权限,再取详情

核心原则

  1. PostgreSQL 是唯一的 System of Record,保存所有权威数据(文件、chunk、图谱结果、状态);
  2. Milvus / Neo4j 只是从 PG 派生的索引/投影,可随时重建——它们不参与业务事务;
  3. 写入时只保证 PG 事务,同步到衍生库是异步 best-effort,失败重试/重放,不存在"脏数据";
  4. 删除时以 PG 标记删除为权威,衍生库清理异步进行(即使清不掉,检索时回 PG 校验也能挡住)。

业界参考

  • Cache-Aside:MySQL(权威)+ Redis(缓存,清空可从 MySQL 重载)——最经典的 SoR 模式;
  • 搜索:MySQL + Elasticsearch 索引(outbox 同步,索引可从 MySQL 重建);
  • 电商 Outbox 模式:订单 + outbox 同事务,worker 发消息给下游(库存/推荐/搜索),各下游维护自己的 projection;
  • RAG 场景:文档库(权威)+ 向量索引(embedding 是派生数据,文档变更重新向量化即可重建)。

改造步骤(分阶段,可独立合入)

Phase 1 —— 最小改动,先堵住两个 P1

Phase 2 —— 引入 Outbox

  • 新增 outbox 事件表(同事务写入);
  • 新增消费 worker(可复用现有 arq worker),异步同步到 Milvus/Neo4j;
  • 幂等消费(事件带 file_id/chunk_id,重放安全)。

Phase 3 —— 对账与自愈

  • 定期对账任务:比对 PG 与 Milvus/Neo4j,清理孤儿(PG 已删但衍生库残留 / 反之重建缺失索引)。

收益

代价

  • 重构入库/删除/图谱构建主流程;
  • 引入 outbox 表 + 消费 worker;
  • 检索链路增加"回 PG 校验"一步(性能成本低,可用 file_id 主键查询)。

关联 issue

#867#876#878#879 均为本问题实例。若方向认可,建议在本 RFC 下讨论后按 Phase 分步实施。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions