ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于Java的工业数据可视化大屏:从PLC采集到质量追溯实战

基于Java的工业数据可视化大屏:从PLC采集到质量追溯实战 车间里的PLC一直在亮灯传感器每一秒都在往外吐数据但这些数据绝大多数时候都躺在控制系统里睡大觉。直到我接到一个任务把全厂产线的实时状态、质量追溯链路做成一块块放在车间和办公室的屏幕上让厂长不用打电话问班组长也能知道当前每个工位发生了什么。这个项目覆盖了我们工厂几条主力产线核心是基于Java的大数据可视化体系把设备采集、消息缓冲、实时聚合、大屏渲染和质量追溯全部串起来。前前后后折腾了一年半从零开始搭数据链路又因为各种莫名其妙的问题连续加班排查。这篇就把它拆开讲重点不是某个框架怎么用而是这套东西在企业生产场景里到底该怎么设计、怎么落地以及那些不跑到一线踩坑就根本学不到的经验。1. 生产车间的数据为什么需要一张会说话的屏1.1 人工报表模式的信息滞后与数据孤岛没上系统之前车间管理基本靠三样东西白板、Excel和电话。班组长每隔两个小时在白板上手写一次产量质检员把抽检结果登记在纸质表格里每天下班前再由统计员把这些数据汇总成Excel发给各部门。这套流程听了就觉得头大实际跑起来更是灾难。上午十点产线已经停了半小时管理层的邮箱里还躺着昨天的一堆报表等层层电话确认下来停机原因可能早就被现场人员自己解决了但这个过程中损失的时间已经追不回来。质量追溯就更痛了。客户投诉一批货有问题需要知道这批货是哪个班次、哪台注塑机、哪一组原料做的只靠纸面记录基本就是大海捞针。我们还真遇到过翻了一周纸档都查不到的情况最后只能给客户赔付了事。这类事情发生的次数多了业务部门自然就有强烈的意愿去推动数字化而不是我们IT部门单方面觉得应该搞个大屏。1.2 为什么选Java而不是更时髦的技术栈在项目启动评审会上有人提议用Python写数据处理前端再配一套现成的开源BI。我当时的判断是不靠谱。原因很简单这家工厂的ERP、MES、WMS系统清一色Java技术栈团队成员也都是Java背景底层数据库和第三方系统的接口文档全是Java生态的。引入Python当然能做数据分析但后续维护成本很高还要多养一条技术线。Java在这个场景里的核心优势是存量集成。生产数据要跟ERP的工单对接跟WMS的物料批次对接跟SCADA的设备数据对接这些系统绝大多数都提供了Java SDK或者JAR包。即使有些老系统没有SDK也会有现成的JDBC驱动或者HTTP接口封装可以参考。大数据生态也不例外Kafka、Flink、Spark、ClickHouse这些组件的Java API都是生产环境验证过的周边资料也最全。选Java本质上是选了整个企业软件体系里的最大公约数。2. 全流程监控的数据链路设计从PLC到可视化大屏2.1 数据采集层兼容存量设备与新增设备工厂车间的设备状态是典型的信息孤岛。我们的产线上同时存在三种设备老式注塑机只有简单的RS485通讯口没有标准协议新一点的数控机床支持OPC UA还有一批完全哑设备什么都没有只能靠外接传感器读取电流和振动数据。我们在每台设备旁边加装了一台工业边缘网关统一做协议转换。网关向下通过Modbus TCP去轮询寄存器通过OPC UA去订阅节点变化向上通过MQTT协议把标准化之后的数据推送到数据中心。采集粒度分了两档设备状态类的开关机、待机、报警每5秒推一次这类数据变化慢不需要太高的频率工艺参数类的温度、压力、转速每30秒推一次为了让实时曲线不至于太跳同时降低网络和下游处理压力。2.2 Kafka为什么采集端和服务端中间必须有一层缓冲最早我们试过让采集服务直接把数据写到MySQL结果设备量一上来就翻车了。产线全部启动的时候设备状态消息有几百条每秒再加上参数消息MySQL的写入连接直接被打满业务查询也被拖慢。后来老老实实加了Kafka这套系统才算站稳。Kafka在这里干了两件事。第一是削峰填谷采集网关按照自己的节奏把消息投递到Topic里下游消费服务按照自己的处理能力一点点消费不会再出现写入洪峰把数据库打爆的情况。第二是数据重放这是生产环境里最救命的功能。某个下游服务因为代码bug挂掉了半个小时正常情况下这半小时的数据就丢了但只要Kafka里的消息保留期没有过服务重启后可以接着消费把缺口补上。我们生产环境的Topic保留期设了48小时足够覆盖大多数故障处理时间。分区设计上每条产线分配一个分区。这样做的好处是同一产线的事件天然有序不会出现设备状态更新的乱序问题。后续如果产线扩充再增加分区也不难。2.3 存储设计热数据与冷数据分流大屏监控和数据追溯对存储的诉求完全不一样。监控看的是此刻正在发生什么追溯查的是历史某个时间点发生了什么。如果都扔进同一个数据库两边的查询会互相影响。我们最终把存储分成了三层存储组件承载场景数据时效核心特点Redis大屏实时卡片、设备最新状态秒级单点查询极快只存最新状态ClickHouse趋势图、聚合分析、近期明细天级/90天列式存储聚合查询性能强MySQL分表质量追溯明细、归档数据永久事务能力支持复杂关联查询实时监控大屏上那些当前在线设备数量今日合格率之类的KPI其实不需要查数据库直接从Redis里取即可。每台设备的状态在采集进Kafka的同时会同步更新Redis里对应的Key大屏接口只做一次GET操作性能几乎不损耗。需要画趋势图的时候再用ClickHouse。比如过去1小时注塑A线温度变化这种查询如果在MySQL里做要扫大量的行ClickHouse的MergeTree引擎天然擅长这种时序聚合加上我们做了按天分区查询基本都能在几百毫秒内返回。MySQL则只承担追溯类的明细写读以及高可靠归档数据量大了就按月分表。3. 可视化接口与前端渲染的搭配逻辑3.1 后端接口要喂半成品不要给前端原材料大屏项目常见的失败原因之一是后端把所有明细数据一股脑返回给前端指望前端去算。我在这个项目里吃过亏所以特别强调一点接口返回的数据结构必须长在图表上。什么意思就是后端直接把一个折线图需要的xAxis时间序列数组和series数值数组算好把仪表盘需要的当前值、目标值、单位返回好前端拿到之后直接填给图表组件不做任何聚合运算。原因很简单浏览器端的算力是有限的几十个图表、每秒钟刷新一次如果每次都要在JavaScript里执行循环聚合页面很快就会卡死而后端服务器做这个计算几乎免费。每个大屏组件对应一个独立接口接口内部再用并行调用方式聚合各个数据源的指标。这样做虽然接口数量多了但单个接口结构简单、职责单一排查问题时也比一个万能接口清晰得多。3.2 ECharts在大屏里的组装套路图表库我们选了ECharts没有太多的纠结。一方面它的中文文档和社区案例是几个开源库里最丰富的遇到问题一搜就有答案另一方面它对JSON配置极其友好后端返回的option配置直接setOption就能渲染省去了前端做数据转换的环节。生产监控场景里反复出现的图表类型很固定环形图用来展示完成率和合格率折线图展示温压趋势轮播列表展示设备报警信息还有车间布局示意图用来标注每台设备的实时状态。ECharts在这几类图上的表现都够用尤其渲染几千个数据点的折线图时没有明显的卡顿。大屏布局我们用24栅格来划分从上到下分三个区域顶部一条放核心KPI卡片包括今日产量、一次合格率、OEE和设备综合效率中部是车间地图和主要产线的状态看板底部滚动显示各个工位最近一条关键参数。这个布局放在车间电视上不需要任何人操作路过扫一眼就能知道现场大概情况。3.3 WebSocket推送与轮询的取舍刚开始做实时刷新的时候第一反应是前端定时轮询接口3秒拉一次全部数据。但这个方案在四块大屏同时开启之后很快就撑不住了后端接口QPS直接翻了几倍高峰期出现大量超时和排队。后来改成WebSocket长连接推送体验有了质的提升。客户端连接建立后后端先把整块大屏需要的完整数据快照推过去之后每5秒推一次增量变化。实现上用的是Spring WebSocket模块加STOMP协议前端订阅对应的Topic即可。这里有几个容易踩的细节。第一服务端必须配置心跳检测和空闲超时否则车间网络里的交换机或者代理会把空闲连接掐掉客户端就会变灰第二断线重连后必须能重新收到一份完整快照否则屏幕上会出现部分数据缺失的花屏状态第三多块大屏要用不同的订阅分组我们一开始没有做分组隔离所有屏幕收到全量数据浪费了大量带宽数据安全上也是个隐患。4. 质量追溯系统的核心逻辑批次、序列号与数据血缘4.1 最小追溯单元从批次到单品序列号质量追溯到底要追到哪一层这个问题必须最先定下来因为它直接决定了采集和管理的工作量。按批次管理是最基础的做法比如一批原料的合格证、一批零件加工时的工艺记录按单品管理则是更严格的追溯每一个成品身上有唯一序列号扫码就能调出它整个生产履历。实际操作中全单品追溯的成本非常高。每个单品都要生成条码或RFID标签每一道工序都要单独记录数据量和采集设备成本都会成倍上涨。我们和业务部门反复讨论后采用了一个折中方案核心安全件按单品序列号管理其他一般件按批次管理。具体的实现是在ERP工单下发的时候就拆分出两个追溯级别系统里用不同的标识符区分。这样既满足了客户对关键件的追溯要求又没有把系统成本推到无法承受的地步。4.2 数据血缘链的设计与存储追溯的本质是把原料批次、设备编号、工序参数、操作人员、检验结果、成品序列号串成一条线。很多项目一上来就想着用图谱数据库我觉得没必要。工业追溯的数据结构其实是标准的主从关联用关系型数据库就能处理得很好。我们建了一张核心的追溯主表表里的trace_id就是贯穿全流程的线头字段名类型说明trace_idvarchar(64)追溯链路唯一ID按产品序列号生成serial_novarchar(64)成品序列号source_batch_idvarchar(64)源头原料批次号process_codevarchar(32)工序编码device_idvarchar(32)设备编号operator_idvarchar(32)操作工IDparam_snapshotjson关键工艺参数快照inspect_resultvarchar(8)该工序检验结果create_timedatetime记录生成时间每一道工序完成时系统都会往这张表插入一条记录同一个成品的所有工序记录共享同一个trace_id。需要正向追踪时拿原料批次号就能查到所有关联的成品需要反向回溯时拿成品序列号直接通过trace_id捞全部记录。不需要做图遍历不需要递归查询一条SQL带索引就走完了。4.3 追溯查询的索引实践与性能优化追溯查询开发完了之后我们做了一个压测数据量到500万行单次完整追溯查询耗时飚到4秒多。一开始怀疑是服务器慢用EXPLAIN一看才发现索引设计有问题。反向回溯场景成品序列号查原料要用trace_id我们建了唯一索引正向追踪场景原料批次查成品要用source_batch_id我们建了组合索引。但还有一个常见场景是操作工PC端按时间范围分段缩小查询范围之前没索引就回调全表。我们在create_time和serial_no上做了联合索引把这类查询也拉回到百毫秒级别。还有一个细节值得提醒代码里查追溯链路时尽量别把多个条件用OR拼在一起。OR条件在很多情况下会让MySQL优化器放弃索引扫描改成全表扫描。实际做法是拆成两个独立查询在应用层合并结果。我们改造之后500万行数据量下一次完整追溯链路查询稳定在200毫秒以内业务部门拿来给客户现场演示都不露怯。5. 项目落地阶段我踩过的坑与排查套路5.1 大屏打开慢、白屏接口超时与并行化改造第一版大屏上线演示的时候最尴尬的一幕是点击打开大屏转圈转了十几秒最后出来了半屏空白。后来定位下来有两个原因。一是前端串行请求十几个图表接口任何一个慢都会拖住整体加载二是后端某些接口内部做了比较重的实时聚合计算需要扫描最近几万条设备数据响应时间本身就要两三秒。我们做了两步优化第一步把所有核心KPI合并成一个聚合接口让首屏只需要请求三四个接口而不是十几个第二步前端把这几个请求改成并行发起而不是上一个回调结束再发下一个。首屏时间从12秒降到了2秒左右。优化之后还发现一个新的瓶颈Tomcat默认线程池在高峰期不够用了接口开始大面积超时。于是又把max-threads从默认值调大并且给IO密集型的聚合查询配置了独立的线程池让大屏接口和业务接口相互隔离这个问题才算根治。5.2 大屏数据和报表对不上时间窗口、时区与浮点精度上线一段时间后业务反馈大屏上的合格率和早会报表总差零点几个百分点。这个偏差单看不大但每天都不一致财务和质检就是不肯在这种数据上签字。我们顺着排查最终锁定三个根因。第一个是统计口径的差异。大屏做得比较着急用了滚动近24小时的时间窗口而报表用的是自然日0点到当前时刻两套口径当然算不到一起。后来在接口里显式接收时间范围参数由调用方传入标准自然日边界保证所有指标同源同口径。第二个是时区问题。数据库连接串没有配置serverTimezone应用服务器和数据库服务器时区不一致导致查询出来的统计结果按不同时区计算日期边界错位了8个小时。给连接串加上serverTimezoneAsia/Shanghai后这个问题立刻消失。第三个是精度问题。合格率计算在Java里用了double做除法造成浮点误差在放大后被前端再放大。排查到这里我们定了规矩涉及金额、数量、占比等统计指标一律用BigDecimal计算数据库字段用decimal(18,4)前端展示取两位小数。从那以后大屏和报表的数字终于能严丝合缝地对上了。5.3 Kafka消费积压导致的实时指标延迟有一阵子运维报警说大屏上的设备状态总比现场慢了一分多钟。我第一反应是WebSocket推送有问题检查了半天没有发现异常。后来去看Kafka的消费Lag发现某个Topic的Lag一直在涨问题根本不在推送而在消费端。排查消费链路的时候发现每条消息处理逻辑里都会查一次MySQL来判断该设备是否存在结果设备消息每秒几百条数据库查询把消费线程全堵住了。修复方案分两步先把设备清单一次性加载到本地缓存消费消息时只查缓存不再访问数据库然后把消费者线程数从最初启动的3个调到和分区数一致的6个让每个线程负责一个分区避免多个线程争抢分区导致的rebalance开销。改完之后Lag在半分钟内清空大屏延迟恢复到了秒级。自动化设备数量的增长和产线改扩建是常态这类问题很容易反复。后来我把This Topic的Lag监控接入了告警系统只要Lag超过阈值就自动告警防患于未然。5.4 追溯查询慢一次典型的SQL索引失效排查前面提到追溯表设计了一套索引但在数据量增长到几百万行后有一类查询还是明显变慢了。我们在页面里按序列号搜索时SQL明明WHERE条件带上了trace_id但EXPLAIN出来的type却是ALL意味着全表扫描。查了半天发现是Java代码在传参时把字符串类型转换成了Long然后MyBatis-Plus在拼SQL的时候带了隐式类型转换。MySQL对字符串列与数字比较时的选择是放弃索引扫描因为函数和类型转换会破坏索引的有序性。解决方案看起来简单得可笑把参数强制转回字符串再传入查询索引立刻生效。但这种问题在生产环境里相当隐蔽因为不是每次都慢而是数据量累积到一定程度才暴露出来。排查这类问题一上来就别去猜直接EXPLAIN看执行计划再对比SQL里的参数类型和字段类型是否一致基本五分钟内能锁定根因。5.5 大屏在不同分辨率下的显示问题车间里的大屏型号比较杂有几台是1080p有几台是竖屏广告机还有一台4K会议屏。最初我们按照固定的1920x1080设计稿来切图结果放到4K屏上所有的字都小得看不清放到竖屏上直接把两侧内容截掉了。试过rem方案发现因为屏幕比例不完全是16:9rem只能解决字体大小解决不了布局错位。最后采用了CSS transform整体缩放的方案大屏容器按设计稿尺寸正常开发页面加载时用JavaScript根据实际屏幕宽度与设计稿宽度的比值计算缩放比例通过transform: scale()应用到最外层容器同时监听窗口尺寸变化实时调整。虽然屏幕边缘会露出背景色但至少核心内容在任何分辨率下都不会错位图表的点击热区也能跟着缩放走。这套方案的代码量很小但效果立竿见影。为了美观我们还在四周加了深色渐变边框把露出来的部分自然融入背景。6. 一些实际体会和可以继续扩展的方向整趟项目走下来我最深的体会是可视化大屏项目80%的精力其实不在画图上而在口径对齐上。如果我们前期没有花几周时间拉着业务部门把产量、OEE、合格率这些指标的定义、计算方式、统计边界逐一确认清楚后期所有图表的返工和争议绝对会把项目拖垮。技术只是实现的最后一步业务口径才是大屏的灵魂。我还有个习惯想推荐给团队做类似项目的朋友在仿真环境里做一次设备数据的峰值压测。不用真的买设备用脚本模拟几百台设备同时上报观察Kafka积压情况、ClickHouse写入吞吐和接口响应时间三个指标。很多问题在几十台设备的小流量下根本暴露不出来但压测一出线程池、连接池、消费能力全部会现出原形。这个环节千万别省。后续这个方向还有几个可以继续扩展的点。一是引入Flink实时计算把设备异常检测从落库后定时扫表改成数据进入Kafka时实时规则判断延迟从秒级降到毫秒级现场报警的及时性会好很多二是做一个可配置的预警规则引擎让工艺人员自己设置阈值、波动范围、停机预测规则而不是每次改逻辑都让我们开发介入三是给质量追溯做移动端入口质检员拿手机扫产品二维码直接看到当前工件的完整生产履历这套追溯能力才算真正用到了日常业务流程里。如果你手头也在做类似的生产监控或质量追溯项目欢迎对照着这套设计思路重新审视自己的数据链路。有些坑我已经替你们踩过了能避开一个是一个。
返回列表