111 lines
7.1 KiB
Markdown
111 lines
7.1 KiB
Markdown
# 架构决策记录(ADR 汇总)
|
||
|
||
> 本文件记录 lingniu-vehicle-ingest v2 的关键架构决策,后续每次重大调整追加条目(不删除旧条目)。
|
||
|
||
## ADR-001 MQ 选型:Kafka
|
||
- **Status**: Accepted
|
||
- **Context**: 需要高吞吐、严格单车有序、成熟生态
|
||
- **Decision**: 使用 Kafka,分区 key = VIN
|
||
- **Consequences**: 下游消费者需使用消费组 + 分区内顺序消费;不使用 RocketMQ 的事务/顺序特性
|
||
|
||
## ADR-002 线上消息格式:Protobuf
|
||
- **Status**: Accepted
|
||
- **Context**: 需要向前兼容、体积小、性能好
|
||
- **Decision**: 线上用 Protobuf,调试/诊断保留 JSON 序列化能力
|
||
- **Consequences**: 需维护 `.proto` schema,`ingest-api` 模块负责生成 Java stub
|
||
|
||
## ADR-003 command-gateway 独立模块
|
||
- **Status**: Accepted
|
||
- **Context**: 下行命令链路不应与接入进程耦合
|
||
- **Decision**: 拆出独立 `command-gateway` 模块,复用 `session-core`;本次重构同步交付
|
||
- **Consequences**: HTTP 对外接口(原 JT808Controller / JT1078Controller)迁移到此模块
|
||
|
||
## ADR-004 信达 Push:Legacy only
|
||
- **Status**: Superseded by ADR-011
|
||
- **Context**: 旧实现硬编码凭证、无重连、0300/0401 空实现
|
||
- **Decision**:
|
||
1. 新模块 `inbound-xinda-push` 隔离第三方库 `gps-push-client`
|
||
2. 配置外置(yml + env)
|
||
3. 自动重连 + Resilience4j 熔断
|
||
4. 0200/0300/0401 **仅做协议解析**,转换为 `VehicleEvent` 后直接投 Kafka
|
||
5. **业务处理全部下沉到下游消费者**,本服务不再实现报警/透传业务逻辑
|
||
- **Consequences**: 信达 Push 现在不属于默认生产面;模块仅保留在 `legacy-xinda` profile,后续优化优先投向 GB32960、JT808、宇通 MQTT、历史和统计链路。
|
||
|
||
## ADR-005 JT1078 / JSATL12 进第一批
|
||
- **Status**: Superseded by ADR-012
|
||
- **Decision**: 第一批迁移即覆盖 JT1078 信令 + JSATL12 报警附件上传
|
||
- **Consequences**: Phase 2 工期相应拉长;JSATL12 需要对象存储后端(本地 / S3 / OSS)
|
||
|
||
## ADR-006 部署形态:GB32960 三应用拆分
|
||
- **Status**: Superseded
|
||
- **Context**: 原 `bootstrap-all` 一体化启动已被 GB32960 拆分部署替代
|
||
- **Decision**: 生产默认部署 `gb32960-ingest-app`、`vehicle-history-app`、`vehicle-analytics-app` 三个应用;旧 `bootstrap-all` 模块删除
|
||
- **Consequences**: CI/CD 分别构建三个镜像;协议接入、历史查询、统计消费可以独立发布和回滚
|
||
|
||
## ADR-007 Java 25 + 虚拟线程 + Disruptor
|
||
- **Status**: Accepted
|
||
- **Decision**:
|
||
- Netty EventLoop 只做解码与 RingBuffer 投递,严禁阻塞
|
||
- 业务 Handler 走虚拟线程(`Thread.ofVirtual()`)
|
||
- 协议间背压通过 Disruptor RingBuffer 表达
|
||
- 禁用 `synchronized`,使用 `ReentrantLock` 避免虚拟线程 pinning
|
||
- **Consequences**: 需开启 `jdk.VirtualThreadPinned` JFR 监控
|
||
|
||
## ADR-008 本服务不写业务库
|
||
- **Status**: Accepted
|
||
- **Decision**: 所有业务表(vehicle_data_actual / history / travel / gps_data 等)不再由本服务写入
|
||
- **Consequences**: 需要新建消费服务 `vehicle-analytics-service` 承接;迁移期采用双跑对账
|
||
|
||
## ADR-009 构建工具:Maven
|
||
- **Status**: Accepted
|
||
- **Decision**: 沿用 Maven,统一 BOM 管理版本,Spotless 格式化,ArchUnit 守护分层
|
||
|
||
## ADR-010 框架:Spring Boot 3.5
|
||
- **Status**: Accepted
|
||
- **Decision**: Spring Boot 3.5.x,支持 JDK 25;AutoConfiguration 用于按需启停
|
||
|
||
## ADR-011 默认生产面:三协议接入 + 历史 + 统计
|
||
- **Status**: Accepted
|
||
- **Context**: 生产接入范围已经从 GB32960 三应用拆分,扩展为三条活跃接入链路和两个消费应用;信达 Push 已废弃,不应再出现在默认构建、部署或优化目标里。
|
||
- **Decision**:
|
||
1. 默认生产面包含 GB32960、JT808、Yutong MQTT、vehicle-history-app、vehicle-analytics-app。
|
||
2. Xinda Push 仅保留在 `legacy-xinda` profile,不进入默认 Maven reactor、Woodpecker 镜像发布和历史消费绑定。
|
||
3. `command-gateway` 和 JT1078 继续作为可选能力,通过 `optional-command-gateway` profile 显式启用。
|
||
- **Consequences**: 默认构建和部署保持精简;后续性能、可靠性、字段解析和存储优化都优先服务三条活跃协议链路。
|
||
|
||
## ADR-012 JSATL12 附件上传:Optional only
|
||
- **Status**: Accepted
|
||
- **Context**: 当前默认生产面只部署 GB32960、JT808、Yutong MQTT、vehicle-history-app、vehicle-analytics-app;JSATL12 附件上传没有独立生产 app,也不在 Portainer 和 Woodpecker 活跃镜像列表中。
|
||
- **Decision**:
|
||
1. `protocol-jsatl12` 不进入默认 Maven reactor。
|
||
2. JSATL12 仅保留在 `optional-attachments` profile,需要附件上传能力时显式构建。
|
||
3. 默认优化和验证优先覆盖活跃接入链路,附件上传能力保持源码可用但不增加默认构建面。
|
||
- **Consequences**: 默认构建更轻,生产部署边界更清晰;附件上传相关测试需要通过 `-Poptional-attachments` 显式运行。
|
||
|
||
## ADR-013 最新状态服务:Optional only
|
||
- **Status**: Accepted
|
||
- **Context**: Redis 最新状态查询是独立消费能力,但当前默认 Portainer 部署和 Woodpecker 镜像发布只包含三条接入链路、history 和 analytics;`vehicle-state-service` 没有独立 app,也不应增加默认构建面。
|
||
- **Decision**:
|
||
1. `vehicle-state-service` 不进入默认 Maven reactor。
|
||
2. vehicle-state-service 仅保留在 `optional-latest-state` profile,需要 Redis 最新状态查询能力时显式构建。
|
||
3. 默认优化和验证优先覆盖活跃接入、TDengine 历史和 MySQL 指标链路。
|
||
- **Consequences**: 默认构建和部署边界继续收窄;最新状态能力保持源码可用,但其测试需要通过 `-Poptional-latest-state` 显式运行。
|
||
|
||
## ADR-014 raw-archive-store 原型实现:Optional only
|
||
- **Status**: Accepted
|
||
- **Context**: 默认生产 raw bytes 写入由 `sink-archive` 负责,历史查询通过 TDengine `raw_frames` 和 `archive://...` 引用追溯;`raw-archive-store` 当前只是独立读写接口和本地实现原型,没有默认 app 或 service 依赖。
|
||
- **Decision**:
|
||
1. `raw-archive-store` 不进入默认 Maven reactor。
|
||
2. raw-archive-store 仅保留在 `optional-raw-archive-store` profile,需要验证本地读写原型时显式构建。
|
||
3. 默认生产链路继续以 `sink-archive`、Kafka raw topic、TDengine raw_frames 为准。
|
||
- **Consequences**: 默认构建少一个未部署模块;本地 raw archive 原型仍可通过 `-Poptional-raw-archive-store` 保留和验证。
|
||
|
||
## ADR-015 文件型事件索引:Removed
|
||
- **Status**: Accepted
|
||
- **Context**: 默认历史查询已收敛到 TDengine `raw_frames`、`vehicle_locations` 和按需解码;旧文件型索引会增加一套无生产部署的查询和依赖边界。
|
||
- **Decision**:
|
||
1. 删除旧文件型事件索引模块和 profile。
|
||
2. 父 POM 不再管理旧索引驱动依赖。
|
||
3. 历史查询和 RAW 回放统一以 TDengine + `archive://...` 引用为准。
|
||
- **Consequences**: 默认构建面和可选构建面都更小;需要历史查询时只维护 TDengine 一条路径。
|