Files
msgexchange-v2/docs/architecture.md
T
windyboy a3f1da4bcc feat(ref): 21 类静态主数据独立 PostgreSQL 参考库边界就位(ACM2-11 落地)
按 ACM2-11 定案调整(业务事务库 MySQL + 航班动态 Redis 不变):
- 接口拆分:RefDataRepository 收为 gen-only(SCHD_GEN/流程 4 CAS,留守业务库);
  新增 StaticRefRepository + RefUpsert 对齐 SOURCE 审计(N19)。
- 调用点:RequestCoordinator 应答落库、ReferenceService(21 类同步 TODO) 指向
  StaticRefRepository;Decision.refUpserts 与 Pump 事务 2 注释同步
  (静态写为弱事务,不入主泵事务 2)。
- Stub:StubRefData 仅 gen;新增 StubStaticRef(内存,保留 source)。
- 配置:datasources.reference / flyway.datasources.reference 占位
  (PostgreSQL,enabled=false 不建连;驱动 org.postgresql 随阶段 6 实装引入,
  版本由 platform BOM 约束 ~42.7);catalog 补 postgresql。
- 文档:README / docs/architecture.md §2/§6 / docs/design.md §2/§6/§9 数据边界
  全部按"21 类 → PG 参考库、gen 留守 MySQL、Redis 动态不变"更新。

验证:37 测试全绿(./gradlew test,接口拆分后无破坏)。
表结构/迁移/ReferenceService 实装/应答接线属阶段 6(U05 批次后)。
2026-09-07 07:56:54 +08:00

12 KiB
Raw Blame History

msgexchange-v2 架构文档

现行架构权威为 Plane airport_chengdu_msgexchange_api 工作区的 ACM2-3(综合架构 v4 脚手架跟踪 ACM2-4,评审与实施计划(U01U30ACM2-10。本文是仓库内的架构速览, 与代码同步维护;两者冲突时以 ACM2-3 为准并回改本文。 配套设计细节见 design.md

1. 系统定位

新一代机场消息交换服务(AODB 报文接入 → 处理 → 对外投递),替换 legacy msgexchange-apiJava 8 / Spring Boot 1.5 / Maven)。过渡策略为双跑三步

影子对拍(同入口双收,比对输出)→ 切流(nextgen 权威)→ 旧仓库冻结
  • legacy 维护不受本仓库影响;本仓库不声明 legacy 旧表 schema(见 §6 数据边界)。
  • wire 契约冻结:消息结构唯一事实源为 SIS_AODB_RMS-V0.1.md + doc/unisysaodbsis.xsd; HTTP 端点路径与响应语义沿用现役(如 POST /cminmsgs/send 返回记录 ID)。

2. 技术栈

选型 说明
语言/运行时 Kotlin 2.3 + JDK 25 JDK 21 不可行(Micronaut 5.1 系要求 JVM 25+ACMA-9 实测)
框架 Micronaut 5.1.3 编译期 DIKSPkotlin-ksp + micronaut-inject-kotlin)生成 *$Definition
持久化 业务库:MySQL + Flyway;静态参考库:PostgreSQLACM2-11 仓储现为接口(Micronaut Data JDBC 实装属 U05,阶段 1 后续;datasources.reference enabled=false 待阶段 6
权威存储 Redis(阶段 A flightInfo hash;仅主泵线程写(I5);Lua 脚本原子覆盖
投递 Kafkaacks=all + 幂等) outbox 模式,经 MSG_EVENT 表中转
投影(阶段 B Elasticsearch + Redis 投影 + FLIGHT_STATE 仅阶段 B 启用(msgx.phase
注册中心 EurekaMicronaut 原生键) 服务名契约 msgexchangeapi(影子 msgexchangeapi-shadow)——U17 未落地:当前注册名仍取 micronaut.application.name=msgexchange-nextgen),msgx.service-name 无运行时消费方(见 §8 与 design.md §9
可观测 logstash TCPAsync 包装)+ MDC traceId + 自定义健康指示器 design.md §8

3. 总体拓扑

                    ┌──────────────────────────────────────────────────┐
                    │                msgexchange-nextgen               │
                    │                (单实例 · 单写者)                │
 AODB/上游 ──HTTP──▶│ ingress                                          │
                    │   InboxService ──事务1──▶ CMINMSGS(原文)        │
                    │                        └▶ PROC_STATEPENDING  │
                    │                                                  │
                    │ processingmsgx-pump 线程,严格 FIFO 队头)       │
                    │   Pump ──tick──▶ MessageProcessor                │
                    │      │                │ decodeXmlCodec        │
                    │      │                │ identity 绑定(I3       │
                    │      │                │ Handler.decide(纯函数)   │
                    │      │─Schd DNLD──▶ SnapshotFlow(流程4         │
                    │      │─PUMP_JOB───▶ JobExecutor(同队列,决策1   │
                    │      │                                           │
                    │      ├────Redis Lua──▶ Redis flightInfoA权威)  │
                    │      └──事务2──▶ MSG_EVENToutbox+ 回填+SUCCEEDED│
                    │                                                  │
                    │ deliverymsgx-dispatcher 线程,每 target FIFO   │
                    │   Dispatcher ──逐条──▶ Kafka(msg)                │
                    │      └─flushSchd 聚合─▶ Kafka(schd)              │
                    │     (阶段 B 追加:ES flight_hts → Redis 投影删除) │
                    └──────────────────────────────────────────────────┘
                                        │                │
                                        ▼                ▼
                                   下游 Kafka topic    Eureka / logstash

要点:

  • 两条专用 daemon 单线程msgx-pump / msgx-dispatcher)由 PipelineLifecycleServerStartupEvent 后拉起,不占用 Netty event loop;停机 requestStop + interrupt + joinU07)。仅当 msgx.pipeline.autostart=true 时装配——生产默认关, 当前属有意脚手架门禁(生产可运行需先完成 U05 数据层实装,见 §7)。
  • 单写者约束(I5:阶段 A 全部 Redis 写集中在主泵线程;实例数必须为 1 (运行期租约/选主保护属 U26,尚未实装,当前靠部署拓扑约束)。
  • 统一 FIFO(决策 1:定时作业(cron → PUMP_JOB 入队)与消息同队列, 作业产物不绕过队头顺序;job 与队头的先后目前为入队时间近似, 统一序号列属 U15(未实装,见 design.md §9 缺口清单)。

4. 模块职责

职责 对应 ACMA-8 主要类
ingress/ 收报事务1:原文落库 + 伴生 PENDING 行;不解析报文 流程 1I3 InboxController InboxService
processing/ 主泵:FIFO 领取、解码、identity 绑定、纯函数决策、事务2 流程 2/4I1/I2/I5 Pump MessageProcessor SnapshotFlow Identity Handler(Registry)
delivery/ 投递:每 target 严格 FIFO、schd 聚合 流程 3 Dispatcher SchdAggregation
jobs/ 泵作业:清场/归档/投影重建(经 PUMP_JOB 同队列) 流程 4/5/7I4 JobExecutor HistorySweepJob ArchiveJob ProjectionRebuildJob
codec/ XML 解码 + 失败分类(MALFORMED vs CODEC_ERROR 决策 4 前置 XmlCodec DecodeResult
domain/ 状态机枚举、事件/决策模型、Phase 开关 I1I5 ProcState MsgEvent Decision MsgKind
infra/ 仓储接口、重试策略、Redis Lua、stub、健康、日志 数据模型节 见 design.md
config/ PipelineProps 参数表(ACMA-8 参数初值) PipelineProps

5. 关键架构决策

# 决策 落点
D1 作业与消息同队列(cron 只经 PUMP_JOB 入队,产物不绕过队头) Pump.tick / JobExecutor
D2 阶段 BES 投递成功后同线程同步 enqueue 删除事件(不轮询 ack Dispatcher.tick(定案 2
D3 schd 唯一出口是 flushSchd 批量聚合(逐条循环显式排除 KAFKA_SCHD) Dispatcher.tickU06/N03
D4 未实装 ≠ 非法:无 handler / staging 未实装 → FAILED(UNSUPPORTED) 可重放,绝不写终态 MessageProcessor SnapshotFlowU10/N21
D5 失败迁移在持有具体 head/batch 的边界完成;loop 只作最后防线,不吞 InterruptedException/Error MessageProcessor DispatcherU08
D6 接口驱动 + 假仓储单测;时间一律经可注入 Clock infra/persistence FailureScheduler
D7 stub 装配门禁:msgx.stubs=true 才装配内存实装;与 autostart 组合支撑 dev 冒烟 infra/stubU07/U01
D8 编译期 DI(KSP)+ 启动期冒烟测试锁定 BeanDefinition 生成 build.gradle.ktsU01

6. 数据边界

  • 本仓库 Flyway 只建六张辅助表PROC_STATE / MSG_EVENT / REF_DATA / REQ_TRACK / PUMP_JOB / FLIGHT_STATEV2.0.0__aux_tables.sql)。
  • 21 类静态主数据 → 独立 PostgreSQL 参考库ACM2-11 定案;datasources.reference / StaticRefRepository):航空公司/航线/机位/登机桥等静态数据迁出 REF_DATA REF_DATA 仅留守 SCHD_GEN 行(流程 4 gen CAS 与 SUCCEEDED 同事务,见 design.md §2 注); 航班动态权威 Redis(阶段 A flightInfo不变。参考库表结构/迁移/21 类同步实装属阶段 6。
  • CMINMSGS / CMINMSGS_HST / COUTMSGS 等 legacy 旧表归 legacy 仓库维护(冻结期), 本仓库不重复声明;全新空库需先建 legacy schema,否则收报首句 SQL 报表不存在 (README「数据库初始化」节)。
  • 回滚兼容关键:SUCCEEDED 时回填 CMINMSGS.SUBSYSTEM_* + DATE_PROCESSED/STATUS, 旧系统可按自身语义无缝接管(Runbook 第 7 步)。

7. 两阶段权威与当前就绪度

阶段 权威 投递目标 状态
Amsgx.phase=A Redis flightInfo KAFKA:msg、KAFKA:schd 管道骨架+重试闭环已实装;Redis Lua/实仓储属 U05/U09
Bmsgx.phase=B FLIGHT_STATE + 投影 + ES:flight_hts、REDIS:flightInfo 未实施(阶段 2 后)

就绪度(2026-09-07 复核口径):可编译、37 测试全绿、dev stub 进程级冒烟实测可端到端 ./gradlew run 无外部依赖启动 → 收报 200 → /health UP,修复记录见 README「进程级 dev 冒烟」); 生产默认配置不可对外服务——autostart=false 且生产(stubs=false)下仓储无实装、DI 装配 即失败。生产就绪前置:U05(数据层+事务)、U07 fail-fast 定案、U09(快照恢复协议)、 U13(投递毒丸补全)、U15(统一序号)。逐项状态见 ACM2-10「定稿实施计划」。

8. 部署与安全姿态

  • 实例数 = 1(主泵单写者前提);双实例误配当前无运行期防护(U26:租约/DB 锁 + 拒启,未实装)。
  • 影子隔离(目标态;U17/U26 未落地,勿按现状引用):服务名(msgexchangeapi-shadow+ 独立 schema + Redis key 前缀 + 独立 topic 三层隔离;当前代码仅 msgx.register-eureka=false 生效—— Kafka topic 写死字面量 "msg"/"schd"Dispatcher)、FlightRedisClient.eval 无 key 前缀参数、 服务名未接 msgx.service-name(§2)。
  • 网络信任模型/cminmsgs/send 无鉴权(沿用现役内网信任姿态);eureka default-zone 回退 127.0.0.1:8761;口令/端点全部环境变量外置(零入库)。安全节细化属 U28。
  • 管理端点Micronaut 5.1 下 /env 默认禁用/beans 默认 enabled+sensitivedev/影子经 顶层 endpoints.* micronaut.endpoints.*——实测前缀错误时不生效)放开 /env/beans 与 health 明细。工程未引入 micronaut-securitysensitive 的实际拦截行为待 U28 定案。
  • 同名单风险:影子与生产同名同路径会互相收报——切流前必须核对服务名三隔离。

9. 可观测性

  • 日志logstash TCP JSON 通道(Async + neverBlock 降级,logstash 不可达不阻塞业务线程); 结构化生命周期日志(收报/SUCCEEDED/SKIPPED/FAILED/DEAD/毒丸/flush 批次);MDC traceId (当前 = cminmsgsId/eventId,处理片段;贯穿收报→投递属 U12 遗留)。
  • 健康/health 聚合 redis-flight-store / kafka-delivery 自定义指示器——真实 ping 判定(false/异常→DOWN,缺 bean→DOWN),非仅 bean 存在。
  • 指标缺口micrometer 队列深度/投递延迟 gauge 未引入(版本对齐待 U05 批次); DEAD/DLQ 告警出口与一致性哨兵实装(U25)未落地——告警当前以 ERROR 日志为落点。