Files
msgexchange-v2/docs/architecture.md
T
windyboy 8c6bb83b62 docs: 同步信箱生命周期实现口径——§4 缺口收敛、水位空洞老化、回填事实并入 PROC_STATE
message-lifecycle.md:§4 两个崩溃窗口随"终态与回填意图同体同行"消除(不再是缺口,改为
说明剩余未闭环项是回填跨库单写期间的持续失败);§5.1 补空洞老化规则(自增回滚空位会使
水位永久停摆,超出最大提交时延即判永久并放行,只跳过空洞不越过已存在的行);§5.2 补判据
机制(不依赖独立待办表,R 覆盖退避);§3 表格改回填意图与"到期或已达 NOW − R"。
design.md:§2.1 表以 INBOX_CURSOR 取代 BACKFILL_TODO、PROC_STATE 责任补回填事实;
§3.1 收报改为按 ID 区间扫描且不以标记为谓词;§3.3 终态由处理器事务内落库、死信同样可
补写;§6.1 维护作业改为 BackfillService.sweep;§7 补 max-commit-delay/overdue-backfill/
backfill-batch 与 mailbox.processed-value;§8 验证表补"终态未回填不得阻断发现"与"意图随
事务回滚";§9 入口表更新;§10 缺口两则改写为现状与待确认项。
architecture.md:§4 主流程第 1/3/4 步与 §3 存储表同步(水位、回填意图、单事务范围)。
flight-state.md:§2 对象表同步。user-stories.md:US-01/US-09 当前基础与落点改为实现现状、
Q2 口径改为"老化阈值待库方书面承诺"。
2026-09-10 11:00:02 +08:00

12 KiB
Raw Blame History

msgexchange-v2 架构文档

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,权威口径见 flight-state.md)。无 Redis 依赖;ES 历史投影属暂缓的阶段 B。

本文描述架构约束,不代表所有能力已实现;实现缺口见第 9 节。模块交互、状态机和参数详见 design.md,消息生命周期与信箱清除见 message-lifecycle.md,需求见 user-stories.md。历史报文契约仍以 SIS 接口规范XSD 为兼容依据,其他 legacy 资料仅作参考,旧系统行为基线的职责见 README 职责表。

现场供库时目标为 Oracle 11g,否则自建 PostgreSQL;当前只有 PG 实现可运行,Oracle 不是已支持的平台。 航班表结构和处理逻辑见 运营航班状态设计

2. 总体架构

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):处理器在锁事务内完成状态写入、事件与回填待办登记,不直接触碰 Kafka。
delivery 消费待发事件,负责按目标保序、schd 聚合、投递和失败重试。
jobs 回填补偿扫描、航班历史清理与留痕保留期清理;独立 job 线程执行(调度见 design.md §6.1,红线见 flight-state.md §6),不参与 FIFO。
domain / config 领域状态、事件和决策模型,以及运行参数。
infra 仓储(JDBC/stub)、外部适配器、重试、健康检查与日志;通过接口隔离基础设施。

4. 主流程

收报与处理

  1. InboxPoller 默认每秒按 ID 区间扫描水位 W 之后的信箱记录(ID > W不以处理标记为谓词),在自有 PG 中建立 PROC_STATE(PENDING);水位与入队在同一事务推进。重复扫描不能重复入队,中断后由重扫补建。扫描谓词与水位的唯一口径见 message-lifecycle.md §5.1。
  2. 主泵只处理最小未完成 MSG_ID。解析报文、绑定业务身份并去重后,分派给 SCHD/FLOP/FDEL/ADFT 处理器。
  3. 在自有 PG 同一事务内(先取 PIPELINE_LOCK)保存航班状态变更(FLIGHT_SCHD 与明细表)、MSG_EVENT 待发事件、处理终态与回填意图。
  4. 事务提交后,补写共享信箱的处理标记(外部副作用,由回填退避重试与超期强制补写保障)。

投递

DispatcherMSG_EVENT 取出待发事件。普通事件按投递目标和 EVENT_ID 保序;某个目标失败时,不能跳过其队头投递后续事件。

schd 是最新状态通知,不逐条发送中间变化:统一由 flushSchdFLID 聚合,取批次内最新事件后发送。它不提供逐条变更历史,不能与普通事件的 FIFO 语义混为一谈。

5. 必须保持的约束

  • 消息严格 FIFO:队头失败并退避时,后续消息仍不能越过它。只有队头完成或按失败策略进入终态后,队列才继续推进。收报重扫和水位设计必须防止较小 ID 漏入队而被后续消息越过。
  • 动态状态单写者FLIGHT_SCHD 及明细表只由主泵单线程写入。事务内第一步对 PIPELINE_LOCK 单行 SELECT ... FOR UPDATE 互斥;该方案在 PG/Oracle 11g 均无需数据库扩展或额外 DBA 特权。不能通过增加实例或处理线程直接扩容。
  • 身份去重:同一业务身份只能绑定一条有效处理记录,重复报文不应再次产生业务副作用。具体身份组成和重放规则见设计文档。
  • 快照可恢复:快照以 PROC_STATE 成功终态判定重放;每次成功写入推进 STATE_VERSIONOPERATION_DAY 一经确定不可变(见 flight-state.md §2.1)。
  • 物理清除只发生在历史归档:删除一律先标记(FDEL)或由生命周期清除;历史存储未接通时必须删 0 条(见 flight-state.md §6)。

这些约束优先于吞吐量优化。单写者降低了并发复杂度,代价是队头阻塞和吞吐上限;如需并行化,必须先重新定义顺序与状态归属,不能只调整线程数。

6. 数据归属与一致性

存储 承载内容 职责说明
自有 PostgreSQL 单行锁 PIPELINE_LOCK、处理状态与回填事实 PROC_STATE、消费水位 INBOX_CURSOR、待发事件 MSG_EVENT、请求跟踪 REQ_TRACK、航班当前态 FLIGHT_SCHD + 9 张明细表、留痕 SCHD_SNAP_LOG 本系统唯一业务数据库。消息处理、状态推进、处理终态、回填意图与待发事件在单事务内原子提交;本地事务只在此库。
共享 MySQL CMINMSGS 入站信箱、COUTMSGS 出站信箱 外部系统所有。本系统仅执行约定的信箱读写与处理标记回填,不建表、不迁移 schema、不写历史表;由库方按 Q9 执行的清除与历史归档见 message-lifecycle.md §6。兼容 HTTP 入口可按既有契约写入入站信箱。

不使用跨库事务。 PG 事务只能保证“处理结果与待发事件一起提交”,不能覆盖 MySQL 回填或 Kafka 发送等外部副作用。跨存储依靠幂等、重试和持久化补偿恢复;各中断位置的判定与恢复动作统一见 message-lifecycle.md §4,本文不重复。

对外投递按至少一次设计,不承诺端到端恰好一次。Kafka 生产者幂等不能消除应用重启或 outbox 重发带来的所有重复。

7. 关键决策

仅保留仍具约束价值、且无法从正文(§4–§6、design.md)直接推出的决策,按 D1–D4 连续编号供正文与 design.md 引用;其余曾编号条目(严格 FIFO、stub 门控、本地事务、UNSUPPORTED 处理等)已在正文以约束形式表达,不再重复列表。状态只反映是否已落地,不代表决策被撤销。

编号 决策及理由 当前状态
D1 航班清场只在历史写入成功后进行,未接通时删 0 条;未经 FDEL 的清场须先补发删除事件。ES 历史投影(阶段 B)暂缓。 红线已实现于 HistorySweepJob;恢复/去重方案未闭合
D2 动态状态单写者,生产只允许一个活动实例;多实例必须先具备可靠的排他保护。 事务行锁已实现;实例级排他未完成
D3 Kafka 生产要求 acks=allenable.idempotence=truemax.in.flight=1;不允许通过关闭幂等来满足生产接入。 约束未强制:默认 in-flight=5,且可用环境变量覆盖
D4 自有库终态记录只归档到 PROC_STATE_HST,不侵入共享库的表结构或保留策略。 目标表未建,尚无归档作业

8. 部署、切换与运维

部署与安全

  • 生产维持单活动实例,停机时停止接收新任务并等待工作线程退出。已有事务级行锁,但消息认领和整个实例的排他保护尚未完成,不能依靠行锁宣称支持双实例 FIFO。
  • 配置、口令和环境端点通过环境变量提供。兼容写接口沿用内网信任模式,缺少鉴权,必须限制网络访问;管理端点不得直接暴露到生产外网。
  • Eureka 用于服务发现,Logstash 接收结构化日志;日志出口故障不应阻塞业务处理。

替换旧系统

采用“影子对拍 → 切流 → 旧系统冻结”。共享信箱不能让新旧系统同时认领和回填;影子输入使用只读水位或回放。影子环境须隔离 PG schema/实例、Kafka topic 和服务注册身份,并禁止误写生产信箱。切流时保证只有一个权威写者。

可观测性要求

使用消息 ID、事件 ID 关联处理与投递日志;健康检查反映依赖实际可用性,而不只是进程存活。运行中重点关注队列积压、队头滞留时间、投递延迟、重试/DEAD 数量和回填补偿积压。死信和一致性异常需要可执行的告警与重放流程,不能只留一条错误日志。

9. 当前实现与上线门槛

当前已实现收报入队与判重、严格 FIFO 主泵、SCHD/FLOP/FDEL/ADFT 处理器与 PG 单事务写入、outbox 与 schd 聚合投递骨架、回填补偿与航班历史清理脚手架。这些只证明机制可用,不证明生产链路已闭环:默认配置不自动启动管道,真实数据库、信箱与出站适配必须显式开启(msgx.pipeline.autostartmailbox.shared-mysql.enabled、真实 DeliveryPort 适配)。

上线前必须完成并验证:

  • 真实 PG + 共享 MySQL 信箱的端到端处理、补偿与投递,以及出站信箱适配;未闭合的缺口清单见 design.md §10。
  • 航班状态不变量与恢复证据:STATE_VERSION 推进、OPERATION_DAY 不可变、故障中断回滚(见 flight-state.md §3.1、§4、§7)。
  • FIFO 越序、身份去重、FDEL/ADFT、清场顺序与投递故障的回归测试(见 design.md §8)。
  • 单实例排他保护与启动校验、影子隔离、Kafka 生产配置约束——当前配置允许环境变量覆盖 acks/幂等/in-flight,且默认 in-flight 值与 D3 不同,切流前必须按 D3 收敛。
  • 死信与一致性异常的告警、可执行的人工重放流程、端到端追踪、积压指标与安全边界。

验收与进度由 Plane 跟踪,缺口逐项见 design.md §10 与 user-stories.md;航班状态规则统一以 flight-state.md 为准。