Files
msgexchange-v2/docs/architecture.md
T

101 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 架构
## 1. 系统定位与范围
msgexchange-v2 是机场 OMMS 的上游报文处理中间件,用于替换旧版 `msgexchange-api`
它读取 CIIMS、AODB 等系统写入共享 MySQL 信箱的 XML 报文,按顺序更新航班动态,再将结果提供给下游。
本系统负责**收报、解析、状态更新和结果投递**,不生成上游业务报文,不替代 CIIMS/AODB,也不提供 AODB 主数据编辑能力。
- **主要入口**:轮询共享 MySQL 的 `CMINMSGS`
- **兼容入口**`POST /cminmsgs/send`,供现役兼容、手工工具和对拍使用;写入信箱后返回记录 ID,不是生产收报主路径。
- **输出**Kafka 的 `msg` / `schd` 消息、共享 MySQL 的 `COUTMSGS` 出站信箱,以及查询 HTTP 接口;不直接推送前端。
- **当前范围(阶段 A)**:航班当前态落自有 PostgreSQL(`FLIGHT_SCHD` + 资源明细表 + `FLIGHT_ROUTE_POINT`,权威口径见 [implementation.md](implementation.md)「航班域」)。无 Redis 依赖;ES 历史投影属阶段 B。
现场供库时目标为 Oracle 11g,否则自建 PostgreSQLOracle 适配必须通过方言与集成验证后才能作为运行时选项。
本文只描述架构约束与归属,不代表能力已实现:机制见 [implementation.md](implementation.md),前提、不变量与可声明性见 [specification.md](specification.md),对外契约见同文件「契约」,需求见 [requirements.md](requirements.md),参数与代码入口见 [reference.md](reference.md);操作步骤在上线/切流前另立规程(设计阶段只保留前置条件与红线)。历史报文契约以 [SIS 接口规范](legacy/SIS_AODB_RMS-V0.1.md) 和 [XSD](legacy/unisysaodbsis.xsd) 为兼容依据。
## 2. 总体架构
```text
CIIMS / AODB 等上游
│ 写入 XML
共享 MySQLCMINMSGS
│ 轮询未处理记录
┌──────────────── msgexchange-v2(单实例)────────────────┐
│ ingress:发现报文 → PostgreSQL 持久化入队 │
│ │ │
│ processing:取 FIFO 队头 → 解析 / 去重 → 处理器决策 │
│ └─ PG 单事务:航班变更 + 终态 + 待发事件│
│ │
│ jobs:独立维护线程(回填补偿 / 历史归档 / 留痕清理) │
│ delivery:读取 PG 待发事件 → 投递 / 重试 │
└─────────────────────────┬──────────────────────────────┘
├─ Kafkamsg / schd
└─ 共享 MySQLCOUTMSGS
处理结果提交后,再回填 CMINMSGS 的处理标记;失败需补偿。
查询接口读取航班动态,不参与状态写入。
```
收报、处理、投递与维护作业各使用独立线程,不占用 HTTP 事件循环。**航班当前态的写入只发生在持有 `PIPELINE_LOCK` 的事务内**,由主泵串行驱动。
技术栈:Kotlin + JDK 25、Micronaut 编译期依赖注入、JDBC 持久化;数据库变更由 Flyway 管理,只作用于自有 PostgreSQL。依赖版本以 `build.gradle.kts` 为准,不在本文重复维护。
## 3. 模块职责
| 模块 | 职责与边界 |
|---|---|
| `ingress` | 轮询信箱、持久化入队及兼容 HTTP 写入;不解析业务报文。 |
| `codec` | XML 解码,区分非法报文与可修复的解码失败。 |
| `processing` | FIFO 调度、业务身份绑定与去重、领域决策与落库(SCHD/FLOP/FDEL/ADFT):纯领域逻辑只返回决策;Processor 作为事务协调器,在锁事务内完成状态写入、事件与回填意图登记,不直接触碰 Kafka。 |
| `delivery` | 消费待发事件,负责按目标保序、`schd` 聚合、投递和失败重试。 |
| `jobs` | 回填补偿扫描、航班历史清理与留痕保留期清理;独立 job 线程执行,不参与 FIFO(与主泵的互斥见 `INV-18`)。 |
| `domain` / `config` | 领域状态、事件和决策模型,以及运行参数。 |
| `infra` | 仓储(JDBC/stub)、外部适配器、重试、健康检查与日志;通过接口隔离基础设施。 |
代码入口清单见 [reference.md](reference.md)「模块与代码入口」。
## 4. 主流程
`InboxPoller` 发现 → 自有 PG 入队(`INV-2`)→ 主泵按最小未完成 `MSG_ID` 取队头、解码并按业务身份去重 → 处理器在持 `PIPELINE_LOCK` 的同一事务内写航班变更、待发事件、处理终态与回填意图(`INV-17`)→ 提交后回填共享信箱处理标记 → `Dispatcher` 投递 `KAFKA:msg``KAFKA:schd`(至少一次,`INV-10`)。
机制细节各有归属:扫描谓词与水位、分派与事务边界、回填、保序与 `schd` 聚合见 [implementation.md](implementation.md)。
## 5. 必须保持的约束
本节只列约束的**归属**;完整定义与验证映射见 [specification.md](specification.md),实现与演进不得违反:
- 消息严格 FIFO`INV-3``INV-4``INV-5`(发现完整性依赖 `PRE-2`/`PRE-3`)。
- 动态状态单写者与写者集合互斥:`D2``INV-18`
- 身份去重:`INV-9`
- 快照可恢复与运营日不可变:`INV-12``INV-13`
- 航班当前态的物理清除只发生在历史归档之后:`D1`
这些约束优先于吞吐量优化。单写者降低了并发复杂度,代价是队头阻塞和吞吐上限;如需并行化,必须先重新定义顺序与状态归属,不能只调整线程数。
## 6. 数据归属与一致性
| 存储 | 承载内容 | 职责说明 |
|---|---|---|
| 自有 PostgreSQL | 单行锁 `PIPELINE_LOCK`、处理状态与回填事实 `PROC_STATE`、消费水位 `INBOX_CURSOR`、待发事件 `MSG_EVENT`、请求跟踪 `REQ_TRACK`、航班当前态 `FLIGHT_SCHD` + 资源明细表 + `FLIGHT_ROUTE_POINT`、留痕 `SCHD_SNAP_LOG` | 本系统唯一业务数据库。消息处理、状态推进、处理终态、回填意图与待发事件在单事务内原子提交;本地事务只在此库。记录级定义见 [implementation.md](implementation.md)「持久化记录」。 |
| 共享 MySQL | `CMINMSGS` 入站信箱、`COUTMSGS` 出站信箱 | 外部系统所有。本系统仅执行约定的信箱读写与处理标记回填,不建表、不迁移 schema、不写历史表;由库方按 `Q9` 执行的清除与历史归档见 [specification.md](specification.md)「契约」。 |
**不使用跨库事务。** PG 事务只能保证「处理结果与待发事件一起提交」(`INV-17`),不能覆盖 MySQL 回填或 Kafka 发送等外部副作用。跨存储依靠幂等、重试和持久化补偿恢复;各中断位置的判定与恢复动作见 [implementation.md](implementation.md)「中断恢复」。
对外投递按**至少一次**设计,不承诺端到端恰好一次。Kafka 生产者幂等不能消除应用重启或 outbox 重发带来的所有重复。
## 7. 关键决策
仅保留仍具约束价值、且无法从正文与 [implementation.md](implementation.md) 直接推出的决策,按 `D1``D4` 连续编号;其余曾编号条目(严格 FIFO、stub 门控、本地事务、UNSUPPORTED 处理等)已在正文以约束形式表达,不再重复列表。第三列只给证据与偏差指针;可声明性见 [specification.md](specification.md),决策不因状态变化而撤销。
| 编号 | 决策及理由 | 证据 / 偏差 |
|---|---|---|
| D1 | 航班清场只在历史写入成功后进行,未接通时删 0 条;未经 FDEL 的清场须先补发删除事件。ES 历史投影(阶段 B)暂缓。 | 红线见 [implementation.md](implementation.md)「生命周期」 |
| D2 | 动态状态单写者,生产只允许一个活动实例;多实例必须先具备可靠的排他保护。 | 事务行锁见 [implementation.md](implementation.md)「事务边界」;实例级排他属 `PRE-5`,可声明性见 `CLM-6` |
| D3 | Kafka 生产要求 `acks=all``enable.idempotence=true``max.in.flight=1`;不允许通过关闭幂等来满足生产接入。 | 取值见 [reference.md](reference.md) 参数表 |
| D4 | 自有库终态记录只归档到 `PROC_STATE_HST`,不侵入共享库的表结构或保留策略。 | `G-PROC-HST` |