6.7 KiB
6.7 KiB
tags, aliases, date created, date modified
| tags | aliases | date created | date modified | |
|---|---|---|---|---|
|
星期一, 十一月 24日 2025, 5:17:58 下午 | 星期一, 十一月 24日 2025, 5:20:20 下午 |
数据模型双态分离与序列化边界的强制隔离架构设计变更通知 (ECN)
- 编号: ECN-2025-002
- 主题: 数据模型双态分离与序列化边界的强制隔离
- 适用范围: 2.5 章节、02_ 核心数据结构、04_ 序列化与网络协议
- 关联原则: [00_ 数据架构总览与原则.md] 第一原则(零拷贝)、第五原则(面向性能布局)
- 日期: 2025-11-24
1. 变更背景与动因 (Background & Motivation)
1.1 现状问题诊断
在原有的设计文档中(如 02_核心数据结构.md),虽然定义了 TrackData 等 C++ 结构体,但在 04_序列化与网络协议.md 中又引入了 Protobuf 定义。由于缺乏明确的 “使用边界” 界定,开发过程中极易出现以下反模式:
- 性能杀手:在计算密集型的内部模块(如
SignalProcessor)直接使用 Protobuf 生成的类(Generated Classes)作为数据载体。这会导致无法利用 SIMD 指令集(内存未对齐)、频繁的堆内存分配以及 getter/setter 的调用开销。 - 架构耦合:内部业务逻辑与外部通信协议强绑定。一旦修改对外接口字段,必须重构内部核心算法代码。
- 零拷贝失效:Protobuf 的序列化/反序列化本质上是深拷贝操作。如果在内部流水线中过早引入 Protobuf,将直接破坏 [03_ 内存管理与所有权.md] 中建立的零拷贝链路。
1.2 变更目标
建立 “双态数据模型 (Dual-State Data Model)” 架构,强制实施 “序列化边界 (Serialization Boundary)” 管控。确保内部数据流专注于极致计算性能,外部数据流专注于互操作性,两者仅在边界处进行转换。
2. 核心变更规范 (Core Specifications)
2.1 确立“双态数据模型”
系统中的数据将严格区分为两种互斥的形态:
| 特征 | 内部原生态 (Internal Native State) | 外部传输态 (External Wire State) |
|---|---|---|
| 承载实体 | C++ POD Structs (e.g., struct TrackData) |
Protobuf Messages (e.g., message TrackDataMessage) |
| 内存布局 | SIMD 友好 (alignas(16/32),连续内存) |
紧凑编码 (Varint, Tag-Length-Value) |
| 生命周期 | 智能指针管理 (std::unique_ptr + MemoryPool) |
栈上临时对象 或 发送缓冲区字节流 |
| 适用范围 | DataReceiver -> SignalProcessor -> DataProcessor |
DisplayController -> Network -> ClientApp |
| 设计原则 | 性能优先 (Raw Performance) | 兼容性优先 (Compatibility) |
2.2 定义“序列化边界” (The Boundary)
序列化边界是指数据从“内部原生态”转换为“外部传输态”的唯一合法逻辑位置。
- 边界位置:仅限于
DisplayController(数据网关模块) 的ExecutionEngine中。 - 流入:
IDataQueue<DataPacket<std::vector<TrackData>>>(C++ 对象指针)。 - 流出:
std::string或std::vector<uint8_t>(Protobuf 序列化后的二进制流)。 - 禁区:
SignalProcessor和DataProcessor严禁 引用*.pb.h头文件,严禁执行SerializeToString()操作。
2.3 引入“数据映射层” (Data Mapping Layer)
在边界处(DisplayController),引入专门的转换逻辑(Mapper/Adapter),负责将 C++ 结构体字段映射到 Protobuf 消息字段。
// 伪代码示例:在边界处的转换逻辑
void DisplayController::convertToWireFormat(const std::vector<TrackData>& native_tracks, radar::ipc::TrackDataBatch* proto_batch)
{
for (const auto& track : native_tracks) {
auto* proto_track = proto_batch->add_tracks();
// 字段映射:从高性能 C++ 结构体 -> Protobuf 消息
proto_track->set_track_id(track.track_id);
// … 坐标转换、单位换算等 …
// 注意:此处发生了一次从"页锁定内存"到"网络发送缓冲区"的内存拷贝
// 这是为了网络传输格式化所必须付出的代价,但被严格限制在最后一步。
}
}
3. 对现有文档的修订指引 (Documentation Patch)
3.1 对 02_核心数据结构.md 的修正
- 新增声明:在文档开头显著位置声明:“本文档定义的结构体为内部原生态对象,仅用于模块间的高性能内存交换。这些结构体不是网络传输协议。”
- 强化定义:确保
DetectionResult和TrackData保持纯粹的 POD 特性,移除任何可能暗示序列化的辅助方法(如toJson()或toProto()),这些方法应移至工具类中。
3.2 对 04_序列化与网络协议.md 的修正
- 明确角色:明确指出
.proto文件定义的是外部契约,而非内部实现。 - 新增章节:添加 “4.4 序列化边界与映射策略”,详细描述数据如何在
DisplayController中从 C++ 结构体转换为 Protobuf 消息。
3.3 对 03_内存管理与所有权.md 的补充
- 补充说明:在零拷贝流程的最后阶段(数据网关),明确说明“零拷贝”在序列化边界处终止。序列化过程不可避免地涉及内存读取和重新编码,这是将数据送入网络栈(Socket Buffer)的必要步骤。
4. 优势分析 (Benefits Analysis)
通过实施此补丁,系统架构将获得以下显著收益:
- 计算性能最大化:内部算法(如卡尔曼滤波、关联矩阵计算)直接操作内存对齐的 C++ 数组,能够充分利用 CPU 的 L1/L2 缓存和 SIMD 指令集,性能相比操作 Protobuf 对象提升 5-10 倍。
- 编译依赖解耦:核心业务模块(
SignalProcessor等)不再依赖 Protobuf 库。如果未来更换序列化协议(如从 Protobuf 换为 FlatBuffers),只需修改DisplayController中的映射层,核心算法代码零修改。 - 内存安全屏障:内部使用强类型的 C++ 结构体,配合
std::unique_ptr管理所有权,消除了直接操作 Protobuf 原始指针可能带来的内存泄漏风险。 - 协议演进灵活性:内部数据结构可以根据算法需求自由优化(例如添加用于调试的临时字段),而无需修改对外的
.proto契约,只需在映射层忽略这些字段即可,实现了内外解耦。
5. 总结
此 ECN 补丁修正了原设计中关于数据形态的模糊定义,建立了**“内部高性能、外部高兼容、边界严管控”**的数据架构范式。这是将雷达数据处理系统从“原型验证”推向“生产级高性能应用”的关键一步。