【MES系统】MES为什么需要SSE?从设备实时监控谈Spring Boot流式推送设计

很多程序员第一次开发 MES(Manufacturing Execution System,制造执行系统)时,都会遇到这样一个需求:

如何让设备状态实时刷新?

看起来,这只是一个很小的功能。

但真正做过 MES 的人都知道,它背后涉及的不仅仅是前端刷新,而是整个系统的数据推送架构。

今天,我们就从一个真实的 MES 场景出发,聊聊为什么越来越多的工业系统开始采用 SSE(Server-Sent Events),以及如何在 Spring Boot 中实现一个高可靠的流式推送架构。


一、MES中的一个真实场景

假设现在有一个离散制造车间。

车间内有 30 台设备正在加工。

MES 首页的大屏需要实时展示:

text 复制代码
设备A:运行中

设备B:待料

设备C:报警

设备D:加工完成

与此同时,还需要实时刷新:

  • 当前工单执行进度
  • 实时产量
  • 设备利用率(OEE)
  • 告警信息
  • 操作员状态

如果采用传统 HTTP 请求,最容易想到的方案就是:

text 复制代码
浏览器
        │
每5秒请求一次
        │
Spring Boot
        │
查询数据库
        │
返回最新状态

刚开始看起来没有问题。

但是随着项目规模扩大,很快问题就出现了。


二、轮询为什么越来越慢?

假设:

一个车间有:

  • 100 个在线客户端
  • 每个客户端打开 3 个实时页面
  • 每 2 秒刷新一次

那么服务器每分钟需要处理:

text 复制代码
100 × 3 × 30 = 9000 次请求

更关键的是:

这 9000 次请求中,大部分返回的数据都是:

text 复制代码
没有变化。

也就是说:

浏览器不停地问服务器:

"设备状态变了吗?"

服务器一次次回答:

"没有。"

这种通信方式显然非常低效。

而真正发生变化的,也许只是:

text 复制代码
09:21:15

设备A:

RUNNING

↓

FAULT

整个系统真正需要推送的数据,其实只有这一条。


三、真正需要的是"服务器主动通知"

MES 更希望采用这样的通信方式:

text 复制代码
设备状态变化
        │
MES收到事件
        │
立即通知浏览器
        │
浏览器更新页面

也就是说:

不是浏览器不停询问。

而是:

服务器有变化再通知客户端。

这就是 SSE 的核心思想。


四、什么是SSE?

SSE(Server-Sent Events)可以理解为:

服务器主动向浏览器持续发送数据。

整个通信过程只有一次 HTTP 请求。

连接建立后:

浏览器一直保持连接。

服务器只要有新的数据:

立即写入连接。

例如:

text 复制代码
Browser
        │
──────────────►
Spring Boot

连接保持不断开

Spring Boot

write()

flush()

write()

flush()

Browser

不断收到数据

整个过程中:

浏览器无需再次发起请求。


五、为什么MES特别适合SSE?

MES 有一个非常典型的特点:

数据变化频繁,但客户端几乎不需要向服务器发送实时消息。

例如:

设备状态:

text 复制代码
IDLE

↓

RUNNING

↓

FAULT

↓

RUNNING

工单状态:

text 复制代码
CREATED

↓

RELEASED

↓

RUNNING

↓

COMPLETED

生产数量:

text 复制代码
356

↓

357

↓

358

↓

359

这些数据:

全部都是:

服务器主动产生。

浏览器只是:

接收。

因此:

SSE 与 MES 的业务模型天然匹配。


六、为什么不是WebSocket?

很多人第一反应:

实时通信就应该使用 WebSocket。

其实未必。

对于 MES 来说:

浏览器主要承担:

text 复制代码
数据显示

真正的数据流:

几乎都是:

text 复制代码
设备

↓

MES

↓

浏览器

浏览器极少需要:

持续向服务器发送消息。

因此:

SSE 已经完全能够满足需求。

相比 WebSocket:

SSE:

  • 基于 HTTP
  • 浏览器原生支持
  • 自动重连
  • 部署简单
  • 更容易经过 Nginx、网关和负载均衡

对于:

  • 实时看板
  • 工单监控
  • OEE监控
  • 告警推送

都是非常合适的选择。


七、Spring Boot如何实现SSE?

Spring MVC 已经提供了现成的支持:

java 复制代码
@GetMapping("/device/stream")
public SseEmitter stream() {
    SseEmitter emitter = new SseEmitter(0L);
    emitterMap.put(userId, emitter);
    return emitter;
}

其中:

java 复制代码
new SseEmitter(0L)

表示:

text 复制代码
永不超时

随后:

当设备状态变化时:

java 复制代码
emitter.send(
    SseEmitter.event()
        .name("device")
        .data(deviceStatus)
);

浏览器立即收到:

javascript 复制代码
eventSource.onmessage = function(event){
    console.log(event.data);
}

整个过程无需再次建立连接。


八、真正的实时推送不是"查询数据库"

各位一定要避免一个误区,就是不停地查询数据库来实现"实时"的效果,这样对资源是极大的浪费

很多项目都会这样写:

text 复制代码
设备变化

↓

更新数据库

↓

浏览器轮询数据库

实际上:

MES 完全没有必要这样设计。

更合理的方式应该是:

text 复制代码
PLC

↓

设备采集服务

↓

发布设备事件

↓

MES状态机

↓

SSE推送

↓

浏览器

设备事件一旦产生:

立即推送。

数据库只是:用于持久化。

而不是:用于实时通信。


九、生产环境需要解决哪些问题?

真正上线后,仅仅使用 SseEmitter 还远远不够。

通常还需要考虑以下几个方面。

1. 连接管理

每一个浏览器都会对应一个 SseEmitter

需要统一维护连接池。

例如:

text 复制代码
ConcurrentHashMap<UserId, SseEmitter>

避免连接丢失。


2. 心跳机制

很多网关会自动断开长连接。

因此:

服务器需要定时发送:

text 复制代码
heartbeat

保持连接存活。


3. 断线清理

浏览器关闭后:

必须及时:

java 复制代码
removeEmitter()

否则:

连接越来越多。

最终导致:

内存泄漏。


4. 自动重连

浏览器网络异常:

SSE 可以自动重新建立连接。

这也是它相比普通 HTTP 更大的优势。


5. 异步推送

设备状态变化:

绝不能阻塞 PLC 数据采集线程。

通常采用:

text 复制代码
设备事件

↓

消息队列

↓

推送线程池

↓

SSE

这样即使:

1000 个客户端在线。

设备采集仍然不会受到影响。


十、MES实时推送的推荐架构

实际项目中,我们更推荐采用事件驱动架构。

text 复制代码
PLC
        │
        ▼
设备采集服务
        │
        ▼
设备事件(Event)
        │
        ▼
MES业务状态机
        │
        ▼
事件总线
        │
        ▼
SSE推送服务
        │
        ▼
浏览器

这里:

SSE 只是:

最后一公里。

真正核心的是:

整个系统采用:

事件驱动。

设备状态变化。

工单状态变化。

告警产生。

生产完成。

都应该抽象成:

统一事件。

这样:

不仅可以推送浏览器。

未来:

消息队列、AI分析、数据湖、BI平台,都可以复用同一套事件流。


十一、结语

很多程序员学习 SSE,关注的是:

Spring Boot 如何使用 SseEmitter

但对于工业软件来说:

真正的问题并不是:

如何推送数据。

而是:

什么时候推?
推什么?
由谁触发推送?

只有把设备事件、MES 状态机和实时推送结合起来,

SSE 才真正成为制造执行系统中的一部分,而不是一个孤立的通信技术。

对于 MES 来说,实时推送的价值,从来不是让页面"动起来"。

而是让设备状态、工单执行和生产过程,以最低延迟、最高可靠性的方式,第一时间传递给真正需要它的人。

相关推荐
陈随易3 小时前
FFmpeg 9.0 发布,代号 Lei,音视频处理再升级
前端·后端·程序员
IT界的老黄牛5 小时前
Spring Boot 的 `/actuator/health` 不是免费的:健康检查打爆连接池的反面教材
spring boot·hikaricp·actuator·健康检查·线上排障·架构反模式
凌虚6 小时前
面向 MySQL 用户的 PostgreSQL 快速上手指南
数据库·后端·架构
都叫我大帅哥6 小时前
Java JJWT 完全指南:从入门到生产级实践
java
IT_陈寒7 小时前
Vite静态资源引用这个坑我踩得有点疼
前端·人工智能·后端
前端开发张小七8 小时前
Java 学习笔记 · 第一课:基础语法与核心概念
java·后端
海盗12348 小时前
微软技术周报 ——2026-08-03
后端·python·microsoft·c#·.netcore
沙湖遇雨8 小时前
6. Pipeline 的生命周期
后端
青青子衿悠悠我心8 小时前
TRAE Work让财务月底对账3小时变5分钟
后端
创安电气研究所8 小时前
用TypeScript给Modbus设备做一层适配器
后端