2. 仿真环境架构设计:微服务 vs 单体、引擎定位与事件驱动

供应链仿真系统从实验性工具走向生产级计划平台,架构选型是决定系统可扩展性、维护成本与仿真吞吐量的关键决策。本章围绕三个核心问题展开:单体架构与微服务架构的适用边界、仿真引擎在系统中的独立定位、以及消息队列如何支撑异步仿真任务与事件驱动协作。

2.1 单体架构 vs 微服务架构:仿真场景的适配性分析

供应链仿真系统通常包含以下功能模块:场景定义、参数配置、仿真引擎、结果存储、可视化看板、用户管理。架构选择直接影响这些模块的耦合度与部署灵活性。

对比维度 单体架构 微服务架构
模块耦合 所有模块运行在同一进程中,函数调用延迟低 服务间通过 API/消息通信,存在网络延迟
仿真引擎扩展 只能垂直扩展(增加单机 CPU/内存) 可独立水平扩展仿真引擎实例
部署粒度 全量部署,修改一处需重启整个系统 按服务独立部署,灰度发布友好
数据一致性 共享数据库,事务强一致 最终一致性,需补偿机制
团队协作 单一代码库,合并冲突频繁 按领域拆分,团队自治
适用阶段 原型验证、团队 < 5 人、仿真场景固定 多租户、多场景并行、持续迭代
架构选型建议: 如果仿真系统仅服务于单一工厂或固定产线,且仿真模型数量少于 20 个,单体架构的开发和运维成本更低。当系统需要支持多工厂、多客户、多场景并发仿真时,微服务架构的独立扩展优势会显著降低仿真排队时间。

2.2 仿真引擎的独立定位:核心职责与边界

在微服务架构中,仿真引擎不应与业务逻辑混在一起。它应当是一个无状态的计算服务,只负责接收仿真参数、执行离散事件模拟、输出结果数据。引擎不关心数据从哪里来,也不关心结果如何展示。

仿真引擎在微服务架构中的独立定位 场景配置服务 参数校验与组装 主数据服务 BOM/工艺/产能 仿真引擎 离散事件模拟 无状态计算 结果序列化 超时熔断 结果存储服务 时序数据写入 可视化看板 图表实时刷新 消息队列(RabbitMQ / Kafka) 异步解耦:请求入队 → 引擎消费 → 结果回写
引擎边界原则:
  • 不直接访问数据库:所有输入参数由上游服务通过消息或 RPC 传入。
  • 不包含业务规则:如“库存低于安全库存时触发补货”属于策略层,引擎只执行模拟逻辑。
  • 结果格式标准化:输出统一为 Protobuf 或 Avro 序列化数据,下游服务按需转换。

2.3 消息队列与事件驱动:异步仿真任务调度

供应链仿真场景通常耗时较长(从几秒到几十分钟),同步调用会阻塞用户操作。引入消息队列后,仿真请求变为异步事件流,系统吞吐量可提升 5~10 倍。

2.3.1 事件驱动架构的核心流程

  1. 用户提交仿真请求 → 前端调用 API 网关。
  2. 场景配置服务 校验参数,生成仿真任务 ID,将任务消息发布到 simulation.task 队列。
  3. 仿真引擎消费者 从队列拉取消息,执行模拟计算。
  4. 引擎完成计算 → 将结果消息发布到 simulation.result 队列。
  5. 结果存储服务 消费结果消息,写入时序数据库。
  6. 可视化看板 通过 WebSocket 推送进度与结果。
事件驱动仿真任务调度流程 用户 / API 网关 场景配置服务 任务队列 simulation.task 仿真引擎 结果队列 simulation.result 结果存储服务 可视化看板

2.3.2 消息队列选型对比

特性 RabbitMQ Apache Kafka
消息模型 队列 / 交换机绑定 分区日志
吞吐量 万级/秒 百万级/秒
消息顺序 单队列有序 分区内有序
消息持久化 支持,但高吞吐下性能下降 磁盘顺序写,持久化友好
重试与死信 内置死信队列 需自行实现重试逻辑
适用场景 任务分发、RPC 解耦 事件流、日志聚合、高吞吐
工程避坑: 仿真任务消息体不要携带完整模型数据(如全量 BOM 或工艺路线),否则消息体积过大导致队列积压。正确做法是消息体只包含 taskId、scenarioId、参数哈希,引擎启动时从对象存储拉取模型文件。

2.4 架构落地检查清单

  • 引擎无状态化:所有仿真实例可被随时销毁和重建,不依赖本地磁盘状态。
  • 消息幂等性:消费者侧实现去重逻辑,防止重复消费导致结果重复写入。
  • 超时与熔断:引擎处理超时(如 > 30 分钟)时,自动将任务重新入队并标记异常。
  • 结果分页:仿真结果可能超过 10 万行,引擎应支持分页输出,避免内存溢出。
  • 监控埋点:在消息生产和消费两端埋点,记录队列深度、处理延迟、失败次数。
架构决策总结: 单体架构适合快速原型和固定场景;微服务 + 消息队列 + 无状态引擎的组合适合生产级多租户仿真平台。仿真引擎的独立定位是架构成功的关键——它只做一件事,但做到极致。