2. 仿真环境架构设计
供应链仿真系统从实验性工具走向生产级计划平台,架构选型是决定系统可扩展性、维护成本与仿真吞吐量的关键决策。本章围绕三个核心问题展开:单体架构与微服务架构的适用边界、仿真引擎在系统中的独立定位、以及消息队列如何支撑异步仿真任务与事件驱动协作。
2.1 单体架构 vs 微服务架构:仿真场景的适配性分析
供应链仿真系统通常包含以下功能模块:场景定义、参数配置、仿真引擎、结果存储、可视化看板、用户管理。架构选择直接影响这些模块的耦合度与部署灵活性。
| 对比维度 | 单体架构 | 微服务架构 |
|---|---|---|
| 模块耦合 | 所有模块运行在同一进程中,函数调用延迟低 | 服务间通过 API/消息通信,存在网络延迟 |
| 仿真引擎扩展 | 只能垂直扩展(增加单机 CPU/内存) | 可独立水平扩展仿真引擎实例 |
| 部署粒度 | 全量部署,修改一处需重启整个系统 | 按服务独立部署,灰度发布友好 |
| 数据一致性 | 共享数据库,事务强一致 | 最终一致性,需补偿机制 |
| 团队协作 | 单一代码库,合并冲突频繁 | 按领域拆分,团队自治 |
| 适用阶段 | 原型验证、团队 < 5 人、仿真场景固定 | 多租户、多场景并行、持续迭代 |
架构选型建议: 如果仿真系统仅服务于单一工厂或固定产线,且仿真模型数量少于 20 个,单体架构的开发和运维成本更低。当系统需要支持多工厂、多客户、多场景并发仿真时,微服务架构的独立扩展优势会显著降低仿真排队时间。
2.2 仿真引擎的独立定位:核心职责与边界
在微服务架构中,仿真引擎不应与业务逻辑混在一起。它应当是一个无状态的计算服务,只负责接收仿真参数、执行离散事件模拟、输出结果数据。引擎不关心数据从哪里来,也不关心结果如何展示。
引擎边界原则:
- 不直接访问数据库:所有输入参数由上游服务通过消息或 RPC 传入。
- 不包含业务规则:如“库存低于安全库存时触发补货”属于策略层,引擎只执行模拟逻辑。
- 结果格式标准化:输出统一为 Protobuf 或 Avro 序列化数据,下游服务按需转换。
2.3 消息队列与事件驱动:异步仿真任务调度
供应链仿真场景通常耗时较长(从几秒到几十分钟),同步调用会阻塞用户操作。引入消息队列后,仿真请求变为异步事件流,系统吞吐量可提升 5~10 倍。
2.3.1 事件驱动架构的核心流程
- 用户提交仿真请求 → 前端调用 API 网关。
- 场景配置服务 校验参数,生成仿真任务 ID,将任务消息发布到
simulation.task队列。 - 仿真引擎消费者 从队列拉取消息,执行模拟计算。
- 引擎完成计算 → 将结果消息发布到
simulation.result队列。 - 结果存储服务 消费结果消息,写入时序数据库。
- 可视化看板 通过 WebSocket 推送进度与结果。
2.3.2 消息队列选型对比
| 特性 | RabbitMQ | Apache Kafka |
|---|---|---|
| 消息模型 | 队列 / 交换机绑定 | 分区日志 |
| 吞吐量 | 万级/秒 | 百万级/秒 |
| 消息顺序 | 单队列有序 | 分区内有序 |
| 消息持久化 | 支持,但高吞吐下性能下降 | 磁盘顺序写,持久化友好 |
| 重试与死信 | 内置死信队列 | 需自行实现重试逻辑 |
| 适用场景 | 任务分发、RPC 解耦 | 事件流、日志聚合、高吞吐 |
工程避坑: 仿真任务消息体不要携带完整模型数据(如全量 BOM 或工艺路线),否则消息体积过大导致队列积压。正确做法是消息体只包含
taskId、scenarioId、参数哈希,引擎启动时从对象存储拉取模型文件。
2.4 架构落地检查清单
- 引擎无状态化:所有仿真实例可被随时销毁和重建,不依赖本地磁盘状态。
- 消息幂等性:消费者侧实现去重逻辑,防止重复消费导致结果重复写入。
- 超时与熔断:引擎处理超时(如 > 30 分钟)时,自动将任务重新入队并标记异常。
- 结果分页:仿真结果可能超过 10 万行,引擎应支持分页输出,避免内存溢出。
- 监控埋点:在消息生产和消费两端埋点,记录队列深度、处理延迟、失败次数。
架构决策总结: 单体架构适合快速原型和固定场景;微服务 + 消息队列 + 无状态引擎的组合适合生产级多租户仿真平台。仿真引擎的独立定位是架构成功的关键——它只做一件事,但做到极致。