第十三章 微服务划分:复杂业务场景下的拆分与规约
本章导读:前三章搞定了数据从接入、治理到存储的全链路,本章切换到应用架构层——业务逻辑该怎么切? 微服务拆分在互联网行业已是常规操作,但在工业场景中有三个独特挑战:业务边界模糊(设备报警到底归报警服务还是设备服务?)、实时性约束严苛(安全联锁不允许跨服务调用的延迟)、以及团队能力参差不齐(不能按照Netflix的标准来要求煤化工的开发团队)。本章讲我们如何在这些约束下找到合理的拆分边界,以及那些"拆过头"和"不敢拆"的教训。本章的拆分结果直接影响下一章(第十四章·技术规范白皮书)的团队协作规范。
在第九章和第十章完成了数据治理和存储选型之后,我们终于来到了"怎么写代码"的核心命题——微服务的划分。对于拥有七大业务领域、数十个子系统的智能工厂平台,若采用传统的单体架构,任何一个子系统的升级都需要全平台停机。但如果拆分过于激进,又会陷入"微服务地狱"——上百个服务之间的调用关系错综复杂,出了问题没人敢碰。
在化工行业落地微服务,最大的陷阱不是"拆多了"或"拆少了",而是拆错了边界。
一、工业微服务不等于互联网微服务
互联网行业的微服务拆分通常以"用户体验"为导向——登录服务、购物车服务、推荐服务各自独立,彼此耦合度低。但在工业场景中,业务逻辑之间的耦合极其紧密。
以"物料投料"这个看似简单的操作为例:它同时涉及库存扣减(仓储域)、批次更新(生产域)、质量标识变更(质检域)和进度上报(调度域)。如果将这些功能强行拆散到四个微服务中,一旦网络闪断导致"库存已扣但批次未更新",在缺乏分布式事务支持的情况下,数据修复的代价是巨大的。
结论: 在工业领域,微服务应是**“业务自治的最小单元”,而非"代码逻辑的最小单元"**。一个完整的业务事务(如物料投料)不应被拆开。
二、领域驱动设计(DDD)的落地
为了避免"乱拆",我们引入了 DDD(领域驱动设计),以**限界上下文(Bounded Context)**作为拆分的标尺。
2.1 核心域的三级拆分
我们沿着化工企业的价值链,将核心业务拆分为三个限界上下文:
计划域(Planning Domain)——“做什么”
- 核心逻辑:对接 ERP 订单,处理生产月计划/周计划
- 数据精度:粒度到"天",关注的是时间维度和总量平衡
- 核心实体:计划(Plan)、合同(Contract)、预算(Budget)
- 在此上下文中,"产品"是一个经营概念——关注库存成本、销售单价和利润空间
调度域(Scheduling Domain)——“谁来做”
- 核心逻辑:将计划转化为具体的作业指令,下发给各装置
- 数据精度:粒度到"小时",关注的是资源匹配和时序逻辑
- 核心实体:工单(Work Order)、班组(Shift)、装置状态(Unit Status)
- 在此上下文中,"产品"变成了调度产量指令——关注产能约束和能耗优化
执行域(Execution Domain)——“怎么做”
- 核心逻辑:实时采集 DCS/PLC 数据,记录生产过程
- 数据精度:粒度到"秒/毫秒",关注的是实时性和准确性
- 核心实体:批次(Batch)、测点(Tag)、单据(Document)
- 在此上下文中,"产品"是物理形态的物料——关注实时流量、纯度和地理位置
通过 DDD 拆分后,我们发现一个关键价值:计划系统的变更(如增加一种统计报表)完全不会影响到执行系统的稳定性。这种基于业务边界的解耦,才是微服务架构在工业落地中的真正价值。
2.2 支撑域与通用域
除了核心生产链条,我们还规划了支撑全局的通用服务:
| 域 | 类型 | 核心职责 |
|---|---|---|
| 人才域 | 支撑域 | 员工档案、考勤、资质管理、专家评定 |
| 风险域 | 聚合域 | 从多个领域提取异常信号,计算风险等级 |
| 认证域 | 通用域 | 统一认证(SSO)、权限管理、TOKEN 签发 |
| 通知域 | 通用域 | 消息推送(企微/短信/邮件/防爆对讲机) |
2.3 领域事件:化解跨域的"一致性焦虑"
在 DDD 架构中,跨限界上下文的通信不应使用同步 RPC 调用(如 Feign/gRPC),因为同步调用会让各域紧密耦合——调度域等着执行域返回结果,执行域等着仓储域确认库存。一旦其中一个环节超时,整条链路全部阻塞。
我们采用领域事件(Domain Events)+ Kafka 消息队列实现最终一致性:
[执行域] 装车完成
↓ 发布事件: ShipmentCompletedEvent
[Kafka Topic: logistics.events]
↓ 消费者1 ↓ 消费者2
[仓储域] 更新库存 [生产域] 更新物料平衡
- "装车发货"事件由执行域发布,仓储域和生产域各自消费,独立更新自己的数据
- 若仓储域消费失败(如数据库暂时不可用),Kafka 消息不会丢失,重试后自动恢复
- 每日凌晨运行跨域对账任务,校验各域数据的最终一致性,差异超过阈值自动告警
这种**“先放行、后审计”**的模式,完美平衡了生产现场的连续性需求与集团管控的严密性要求。
三、集团化管控:消灭考核黑箱
面对陕煤集团多个下属企业,我们做出了一个关键决策:物料平衡的计算逻辑高度集中。
为什么集中? 如果允许各下属企业在自己的执行域内自行计算产量和物耗,就等于把考核的"裁判权"交给了被考核方。在国企环境中,这必然导致数据失真。
我们的架构设计是:
- 各子企业的执行域微服务只负责**“如实上报”**物理计量事件(地磅称重值、流量计积分值)
- 物料平衡计算逻辑和容差标准集中在集团智能运营平台(调度域)
- 集团微服务网关统一接收标准事件,路由到集团分析实例中
- 异常波动(如连续三个班次的物耗偏差超过 2%)自动触发审计预警
这种"执行层如实上报 + 集团层统一裁判"的架构,从技术上杜绝了"数据作假"的空间。
四、接口规范:Swagger 的战略升级
在多部门、多供应商协作的环境下,接口文档就是前置约束条件。我们不再接受 PDF 或 Word 形式的文档,而是将 Swagger(OpenAPI Specification)提升到了战略高度。
4.1 网关层聚合:一个入口管全部
最初每个微服务各自维护独立的 Swagger 页面,前端开发需要保存几十个 URL,切换极其繁琐。我们在**网关层(Gateway)**引入了聚合方案:
- 分组展示: 所有微服务的 API 文档以"分组"形式集成在网关入口
- 自动发现: 微服务上线后自动向网关注册其接口描述文件,无需手动配置
- Mock 环境: 基于 Swagger 契约自动生成 Mock 数据,实现前后端并行开发,将联调周期缩短了约 20%
4.2 强制规范
- 统一错误码: 所有接口遵循统一的响应格式
Result<T>,错误码按业务域分段(如10xxx生产域、20xxx设备域) - 版本管理: API 路径中强制包含版本号(
/api/v1/),不允许直接修改已发布接口的语义 - 变更通知: 后端修改接口字段前必须先更新 Swagger 定义,CI 流水线自动对比前后版本差异,Breaking Change 会触发邮件通知所有调用方
五、遗留系统集成:让老系统"零改造"说话
工厂里往往运行着十年前部署的基于 SOAP 协议的老旧 MES 或早期 ERP。面对这些遗留系统,我们采取了务实的策略:在微服务网关层进行协议转换。
把老系统当做"黑盒",微服务发出标准 RESTful 请求后,网关层拦截并利用插件动态转换为老系统所需的 XML/SOAP 格式,收到响应后反向解析为 JSON。实现了老系统**“零改造”**接入。
教训: 初期为了图省事,开发人员把"计量单位换算"、"物料编码映射"等业务逻辑也塞进了网关插件,导致网关 CPU 负载异常飙升。痛定思痛后我们确立了不可逾越的边界:
网关只做纯粹的"协议与语法转换",坚决不允许触碰"业务语义"。 所有业务数据的清洗和映射,必须交由发起请求的领域微服务自行处理。
六、微服务治理:可观测性与容错
当微服务数量达到数十个,"某个请求到底卡在哪一步"的问题变得极其棘手。我们构建了完整的可观测性体系:
6.1 分布式链路追踪
所有微服务接入 SkyWalking/Zipkin,每个请求分配全局唯一的 Trace ID。当工艺员反馈"趋势图加载慢"时,运维只需搜索该请求的 Trace ID,即可看到请求经过的每一个微服务节点及各节点的耗时——是 TDengine 查询慢还是网关转发延迟一目了然。
6.2 熔断/限流/降级
- 熔断(Circuit Breaker): 当某个下游服务(如设备台账服务)连续失败超过阈值,上游自动"断路",返回缓存中的最近一次有效数据,避免级联故障
- 限流(Rate Limiting): 对外部系统调用 API 设置 QPS 上限,防止第三方系统的异常重试冲垮核心服务
- 降级(Degradation): 在大屏访问高峰期(如集团领导视察),自动降级非核心功能(如历史报表导出),将计算资源集中保障实时看板的流畅度
七、总结
微服务架构在工业互联网中的落地,核心不在于"拆了多少个服务",而在于三条原则是否被坚守:
- 业务边界决定服务边界——DDD 的限界上下文是拆分的唯一标尺
- 最终一致性优于强一致性——领域事件 + Kafka 实现"先放行、后审计"
- 网关只做翻译不做业务——协议转换与业务逻辑严格分离
下一章,我们将从"怎么写代码"深入到"怎么管代码"——在多供应商协作的国企项目中,《技术规范白皮书》如何成为管理混乱、确保交付质量的"核武器"。
1万+



被折叠的 条评论
为什么被折叠?



