问题出在哪
昆山有家电子代工厂,主要给品牌商做笔记本电脑主板,车间里有48台贴片机、12条组装线,每天产生约30万条生产数据。他们的MES系统是2019年找苏州一家软件公司做的,PHP + MySQL技术栈。ERP用的是用友U8。两套系统之间的数据同步靠的是每15分钟跑一次的定时任务。
问题来了。产线上的良率数据要15分钟后才到ERP,品管部门看到的数据总是滞后的。上个月因为同步延迟,一批不良品已经流转到下一道工序才发现,报废了2万多的物料。厂长拍桌子了。
我们接手这个项目后,分析了三种方案:缩短轮询间隔、上消息队列、用CDC(Change Data Capture)。
方案一:缩短轮询间隔
最简单的改法——把15分钟改成30秒。改起来快,加个cron参数就行。但实际跑下来发现两个问题:第一,MES系统的MySQL在高峰期已经有点吃力了,每30秒全量查一次未同步数据,CPU使用率从35%飙到78%;第二,ERP那边的API接口承受不住,频繁调用导致U8的Web服务线程池经常被打满,其他部门的同事投诉报表打不开。
坚持了三天,放弃了。这个方案治标不治本。
方案二:消息队列(RabbitMQ)
第二步,我们在MES系统里加了RabbitMQ。MES每次写入生产数据时,同时往消息队列发一条事件消息,ERP端订阅队列实时消费。架构上没毛病,但实施时踩了坑。
最大的问题是MES的PHP代码是老架构,没有统一的数据写入入口——不同模块各写各的,有的走Model层,有的直接拼SQL。要改的地方太多了,光梳理代码就花了一周。而且开发团队担心改出bug影响生产,不敢大动。
后来我们折中了一下,只改了「检验报告」和「工单完成」两个最关键的写入入口,其他模块保持原样。上线后,这两个关键节点的数据同步延迟降到了3秒以内。但那些没改的模块还是老样子。
方案三:CDC(Debezium)
最后上的方案是CDC。用Debezium监听MySQL的binlog,把数据变更事件实时推送到Kafka,ERP端写了个消费者服务从Kafka拉数据调U8的API。
这个方案最大的好处是——MES系统一行代码都不用改。Debezium在数据库层面工作,感知不到上层应用的存在。binlog本身就是MySQL主从复制的机制,对MES系统性能影响极小,实测CPU额外开销不到3%。
部署花了两周,主要时间花在梳理MES的200多张表,确定哪些表需要同步、字段怎么映射到ERP。上线后所有数据的同步延迟稳定在2秒以内,CPU开销可忽略。
最终方案与效果
三种方案对比下来,CDC是性价比最高的。消息队列方案虽然架构最优雅,但改造成本太高,老系统经不起大手术。轮询方案就是个笑话。
上线两个月后,厂长说品管部门的投诉降了90%,再没出现过因为数据滞后导致的不良品流转问题。估算下来,每年能减少报废损失约15万元。而整个CDC方案的部署成本不到4万。
踩过坑的人都知道,老系统改造最怕的就是大动干戈。能在数据库层面解决的问题,就别去碰应用层代码。这个思路不仅适用于MES,苏州很多传统制造企业的系统集成都能借鉴。