外部数据接入
外部系统不是数据源,是可调用的能力。 大多数「ERP 集成」需求其实是问一个问题,不是要一张表。
三种接入方式
| 模式 | 做什么 | 何时用 | 状态 |
|---|---|---|---|
| 能力集成 | 外部系统注册为 skill,按需调用,结果落事实 | 查询、校验、外部审批、人工能力 | ✅ 可用 |
| 事件接入 | 对方推变更 → 原始事件 → 映射 → 状态层 | 对方是权威且不可替换 | 设计完成,未实现 |
| 只读镜像 | 定期拉快照 + 持续对账 | 最后手段:无 API、无 change feed | 设计完成,未实现 |
对方提供的是「能力」还是「事实」?
├─ 能力(我能问你一个问题)→ 能力集成
└─ 事实(它的状态我必须知道)→
├─ 它能推变更 → 事件接入
└─ 它只能被我拉 → 只读镜像为什么能力集成优先
| 能力集成 | 事件接入 / 镜像 | |
|---|---|---|
| 数据流向 | 按需问一次 | 持续同步 |
| 是否产生第二真相 | 否 | 是 |
| 审计粒度 | 每次调用一条事实 | 每条变更一条事实 |
| 失败影响 | 单次调用失败 | 管道失败可能静默 |
关键点:不复制对方的数据,只记下「问到的答案」。
不把 SAP 的库存表同步过来
而是注册一个 sap-inventory-query 能力
需要时调用 → 拿到结果 → 结果成为一条事实(带 actor 与调用时间)这样不会产生第二个真相源,而且每次调用都可审计。
「第三个真相」怎么产生的
很多团队以为把外部数据同步进来就完事了。实际上:
| 情形 | 可写路径数 | 是否产生第三真相 |
|---|---|---|
| 外部系统 + 只读镜像(镜像拒写) | 1 | 否 |
| 外部系统 + 本系统可写同一事实 | 2 | 是 |
| 再加上人工导表 | 3 | 是(且最常见) |
所以接入的第一条规则不是「怎么同步」,是**「让第二写路径在机制上不可能」**:
某域声明为 mirrored
→ 业务写入一律 403
→ 只有同步管道能写权威归属:避免双余额
| 场景 | 我们的余额 | 外部系统 |
|---|---|---|
| 我们是权威 | 正常扣减 / 记账 | 只读或废弃 |
| 外部是权威 | 只做镜像 + 对账,不参与扣减 | 正常扣减 |
| 双方都写 | 禁止,必须选一个 |
违反这条就会出现两个余额,且无法判断哪个对——这是传统 ERP 集成的经典失败模式。
对账:把「不一致」变成「可查询」
如果确实做了镜像,就必须配一个对账,否则镜像只是另一个会腐烂的副本。
拉对方当前快照
→ 按映射算出「对方应该产生的投影」
→ 与本系统实际投影比对
→ 差异分级:missing / stale / divergent / orphan对账结果本身也要落成事实——这样「什么时候发现过、谁处理的」都进因果链。
一条硬规则:能力集成不暴露注册
外部能力注册接受任意 URL,由服务端发起请求。 如果做成普通用户端点,就等于让任何登录用户访问内网地址(SSRF)。
所以注册走部署配置或管理员通道,只开放调用。
边界
| 不做 | 原因 |
|---|---|
| 全量主数据同步 | 那是 MDM 的领域,且没有实体解析能力 |
| 双向写回 | 两个可写路径 = 两个真相源 |
| 通用 ETL | 会退化成数据集成产品,与「可追责的事实」定位冲突 |
| 自动推断字段语义 | 映射必须显式、版本化、可回溯 |
继续读
- 能力集成的用法 → External Skill
- 为什么按形态分存储 → 存储选型
- 域与权威 → 域模型