ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Node-RED+OPC UA+MySQL:工业数据采集与存储完整方案

Node-RED+OPC UA+MySQL:工业数据采集与存储完整方案 1. 数据采集方案的整体设计与思路拆解1.1 为什么要用Node-RED来完成OPC UA到MySQL的数据通道做工业现场数据采集的工程师八成会碰到这样的场景现场PLC、传感器、仪表的数据需要存到数据库里做历史记录、报表统计或后续分析。传统的做法不外乎两类——买一套组态软件或者工业网关让厂家帮忙配置好数据转发规则或者自己写程序用C#、Python去调OPC UA客户端SDK再自己拼SQL写进数据库。这两条路各有各的麻烦。组态软件和网关价格不便宜而且往往绑定硬件现场加一个点位都要找供应商改配置灵活性很差。自己写程序倒是灵活但开发周期长调试也麻烦尤其OPC UA这种带安全策略、证书认证的协议自己从零搞一遍光握手和加密就能耗掉两三天。Node-RED在这类场景里的价值简单说就是四个字编排快。它是一个基于流的可视化编程工具节点之间用连线把数据处理逻辑串起来OPC UA读取、JSON解析、MySQL写入都有现成的节点可以直接拖。改一个点位、加一条写入规则在界面上拖拽几下就好不用重新编译、重新部署。整体下来从一个空环境到数据能落库熟练的话半小时到一个小时就能跑通。这正是很多做数据采集、设备监控的同学愿意用它的原因。另外要提一下选型。OPC UAOPC Unified Architecture是工业通信里的标准协议相比老一代的OPC DA基于Windows COM/DCOM优势非常明显跨平台、内置安全机制、支持数据模型建模而且不需要再纠结DCOM那套极其脆弱的配置。MySQL则是应用最广的开源关系型数据库之一运维门槛低查询分析方便配合Navicat、Workbench这类工具做可视化查看也很成熟。Node-RED OPC UA MySQL这套组合恰好覆盖了采集-处理-存储整条链路而且每个环节都是成熟方案。1.2 数据链路的架构设计与核心流转逻辑先把我这套方案的完整链路画在文字里现场设备PLC/传感器→ OPC UA服务器 → Node-REDOPC UA客户端节点读取数据→ 函数节点做格式化和清洗 → MySQL节点写入数据库表在实际落地时OPC UA服务器可能是设备自带的比如某些高端PLC、支持UA协议的仪表也可能是通过网关把Modbus、Profinet之类的协议统一映射成OPC UA的比如KepwareEX配合UA插件或者Softing、Matrikon的网关产品。这两种情况对Node-RED来说没有任何区别因为它只认OPC UA这层协议不需要关心上游是什么设备这就大幅简化了数据源的对接工作。读取方式上OPC UA提供了两种模式——轮询读取和订阅机制。我在正式环境里强烈推荐用订阅。轮询就是定时用Read服务去读点位简单直接但每个周期都要发起请求点位多了以后对服务器压力比较大实时性也取决于轮询周期。订阅是客户端向服务器注册一批感兴趣的节点服务器按设定的发布间隔主动把变化或周期性的数据推给客户端负载更小实时性也更高。Node-RED的node-red-contrib-opcua节点库同时支持客户端和服务器端。我们这里主要用客户端节点去连已有的OPC UA服务器后面我会把配置细节一步步拆开讲。数据到达Node-RED之后我习惯先经过一个函数节点做三件事提取有效值字段、统一时间戳格式、补上点位标识和质量码。因为OPC UA返回的数据结构里实际值在value字段里还带着sourceTimestamp、serverTimestamp、statusCode等信息如果不处理就直接丢给数据库写入字段会混乱而且后期做数据分析时时间维度也不统一。然后再到MySQL写入节点用一条INSERT语句落库。这里有个优化项如果采集频率高、点位多一条条INSERT效率很低可以把一个周期内的多条记录拼成一条INSERT INTO ... VALUES (...),(...)的批量语句提交性能提升非常明显。下面章节我会分别讲环境、配置、实操和坑。2. 环境准备与软件安装先把基础设施搭好2.1 Node-RED的本机安装与初始设置我以Windows环境为例因为目前还是很多工控工程师的主力系统其他平台的步骤差别不大。前提是装好Node.js建议装12.x以上的LTS版本太老的版本跑新插件容易出兼容问题。到Node.js官网下载安装包装完在命令行验证一下node -v npm -v然后全局安装Node-REDnpm install -g node-red安装完成后在命令行直接敲node-red就能启动默认监听1880端口。浏览器打开http://localhost:1880看到拖拽式的流编辑界面就算成功了。我建议在启动命令里加两个参数对之后的调试很有帮助node-red --safe --userDir D:\nodered_data--safe是进入安全模式已经部署的流照常运行但新改动先不生效等点部署后再加载--userDir可以指定数据目录把整个工作区、配置文件集中到某个盘重装系统或迁移环境时直接把文件夹拷走就行省得默认目录找半天。如果公司内网服务器是Linux更推荐用Docker方式docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red不管用哪种方式装完之后先确认版本能起来别急着下一步。2.2 OPC UA测试服务器的选择与搭建调试阶段我不建议直接连现场PLC风险太大而且出问题很难定位。先用一个OPC UA模拟服务器把整条链路跑通再接真实设备这个顺序能省掉很多麻烦。常用的免费模拟器有三个我分别说一下适用场景Prosys OPC UA Simulation Server免费的模拟服务器自带一批模拟点位界面清爽支持在线浏览地址空间非常适合初学者熟悉OPC UA的地址模型和节点概念。不需要License直接用。KepwareEX老牌工业协议网关软件本身以OPC DA为主想要OPC UA功能需要装插件UA Server插件是收费的。如果现场已经有KepwareEX调试时可以直接把它当UA服务器用但纯学习意义不大因为License和插件都得花钱。Node-RED自带的OPC UA服务器节点node-red-contrib-opcua库里有一个Server节点可以在Node-RED里直接起一个OPC UA服务器挂几个模拟点位出来。好处是你不用再装别的软件整个环境就在一个工具里全部搞定缺点是没有ACO地址空间的图形化浏览界面新手可能不好理解自定义NodeId的创建方式。我个人的推荐组合是学习阶段用Prosys因为可视化浏览节点树对理解OPC UA地址空间这个概念帮助特别大。Prosys启动后默认端点地址一般是opc.tcp://你的主机名:53530/opcua/server里面会预置很多模拟标签。快速验证用的常用节点ID包括ns2;i1001随机正弦波用于观察连续变化ns2;i1005随机数记一下后面在Node-RED里测连接和订阅会用到。2.3 MySQL安装建库建表MySQL的安装方式有MSI图形安装版、ZIP免安装解压版和Docker版。我自己更常用ZIP解压版因为不污染系统删的时候也干净。到MySQL官网下载Community Server的ZIP包比如mysql-8.x.x-winx64.zip解压到D:\mysql然后在D:\mysql下新建一个my.ini配置文件最小配置如下[mysqld] basedirD:/mysql datadirD:/mysql/data port3306 character-set-serverutf8mb4 default-authentication-pluginmysql_native_password [client] default-character-setutf8mb4这里utf8mb4是必须的如果以后采集的数据里可能有中文标签名或注释用utf8能存但可能有编码问题utf8mb4是utf8的完整版兼容性最好。然后用管理员权限打开命令行进入D:\mysql\bin执行mysqld --initialize-insecure mysqld -install net start mysql--initialize-insecure会生成一个root空密码的初始实例所以初始化完第一件事就是改密码mysql -u root -p ALTER USER rootlocalhost IDENTIFIED BY 你的密码; FLUSH PRIVILEGES;接下来建库建表。我用一张最简单的采集表做示例CREATE DATABASE IF NOT EXISTS opc_iot DEFAULT CHARACTER SET utf8mb4; USE opc_iot; CREATE TABLE IF NOT EXISTS tag_history ( id INT AUTO_INCREMENT PRIMARY KEY, tag_name VARCHAR(128) NOT NULL COMMENT 点位名称, tag_value DOUBLE NULL COMMENT 点位数值, quality INT NULL COMMENT OPC UA质量码, source_time DATETIME NULL COMMENT 设备时间戳, record_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 入库时间, INDEX idx_tag_time (tag_name, record_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENTOPC UA点位历史数据表;字段设计上tag_name用来区分点位tag_value存实际值quality存OPC UA状态码source_time存设备侧发出的时间戳record_time是数据库写入时间。两个时间字段分开存后面排查设备时间和服务器时间不一致的问题时就能直接对比不用来回倒推。表建好后用Navicat或MySQL Workbench连一下确认能访问数据库这步就算到位了。3. 在Node-RED中配置OPC UA节点实现数据读取3.1 安装node-red-contrib-opcua节点库进入Node-RED界面点击右上角菜单三横线选节点管理切到安装标签页在搜索框里输入node-red-contrib-opcua点安装。装完会看到面板左侧新增一大批节点归纳一下主要分这几类OPC UA Client相关OPC UA Client用于创建客户端连接、OPC UA Subscription订阅一组节点、OPC UA Reader单次读取节点值、OPC UA In订阅上报的入口节点OPC UA Server相关OPC UA Server、OPC UA Item定义服务端点位工具类OPC UA Browser浏览远程服务器地址空间、OPC UA Events监听事件、OPC UA Historizer历史数据读取我们这次用到的核心是Client、Subscription和Reader。这三个的定位区别记一下Reader是主动拉一次Subscription是订阅后持续推实际采集用Subscription居多。如果安装时提示失败大概率是npm源网络问题切换一下源再装npm config set registry https://registry.npmmirror.com注意改完后要重启一次Node-RED进程再尝试。3.2 创建OPC UA客户端连接在左侧节点列表找到OPC UA Client节点拖到画布上双击打开配置。关键配置项我逐个说明Endpoint必填。填OPC UA服务器的地址格式是opc.tcp://主机IP:端口/路径。注意这里不要填localhost尤其是Node-RED和OPC UA服务器不在同一台机器时直接用IP最稳妥。后面排查问题也方便。Security Policy安全策略。可选None、Basic128Rsa15、Basic256、Basic256Sha256等。如果OPC UA服务器允许调试阶段建议选None省去证书配置。生产环境再根据实际情况选择加密策略并配置证书。User Name和Password如果服务器启用了账号认证就填上。Prosys这类模拟服务器默认是不开启认证的先不填能连上了再考虑加认证的场景。连接节点配置好之后还要再拖一个OPC UA Subscription节点。这个节点的作用是维护一个订阅任务订阅项可以动态添加。配置里比较重要的是Publishing Interval这个值决定服务器多久推送一批数据单位是毫秒。由于实际项目对实时性要求不高——存数据库嘛一般数据延迟几百毫秒完全能接受——我建议设置为1000ms。设太短比如100ms数据点多了会频繁拉起MySQL写入存储压力很大设太长比如10s实时监控界面看起来又卡顿。OPC UA Subscription节点还需要指定它挂在哪个Client连接上。在节点配置里选择对应的Client实例即可。接下来把OPC UA Client和OPC UA Subscription连线连起来Client的输出连接到Subscription的输入。这一步的逻辑是先有客户端连接才有订阅通道顺序不能反。我先说一下很多新手在这里被卡住根本问题在于没有理解这三个节点的协作模式——Client负责建立连接Subscription负责承载订阅任务Reader才是真正读单个点位的。如果你直接拖一个Reader节点让它读Prosys的模拟点而不先连一个Subscription是读不到持续数据的因为Reader只执行一次性读取返回之后就结束了。3.3 点位订阅与数据输出的实际配置配置Subscription节点时除了连接选择还需要把要订阅的节点添加进去。在Subscription节点配置界面的subscriptions区域点击加号添加一行填写NodeId对应OPC UA服务器里节点的标识。格式一般是ns2;i1001或者ns2;sSimulation_Random。这里的命名空间ns和标识i或s是OPC UA地址空间里的核心概念简单理解ns是命名空间编号i是数字节点IDs是字符串节点ID具体值和服务器里定义的变量绑定。Sampling Interval采样间隔服务器从底层设备读取数据的周期可以设短一些比如100ms。Queue Size队列长度默认1即可除非想缓存历史变化。保存之后在Subscription节点的输出后面接一个调试节点debug部署一下流看看调试面板。正常的输出应该类似{ payload: 12.345, nodeId: ns2;i1001, sourceTimestamp: 2024-01-06T10:01:02.123Z, serverTimestamp: 2024-01-06T10:01:02.124Z }或者直接是一个包含value字段的对象这取决于节点库的具体版本。看到数据能在调试面板里持续变化就说明OPC UA读取这一侧的管道已经通了。这里有个非常关键的细节OPC UA订阅推送过来的数据Payload并不一定总是数值。对于布尔点位、字符串点位或者带状态码的点位结构会不一样。在后面写MySQL之前必须先用一个Function节点把需要写入的数据标准化。我后面给的函数模板会直接把这个问题解决掉。4. 数据写入MySQL从清洗到落库的完整实现4.1 安装node-red-contrib-mysql并配置连接MySQL节点有两个版本比较知名官方维护的node-red-contrib-mysql和mysql-r分支模式。我推荐用node-red-contrib-mysql因为它提供的节点比较直观一个mysql节点做连接管理一个query节点负责执行SQL还有一个query,multi节点支持批量查询。安装方法同上在节点管理的搜索框输入node-red-contrib-mysql点安装。拖一个mysql节点到画布双击配置HostMySQL所在机器的IP本地就是127.0.0.1。Port默认3306。Userroot或者单独建的采集账号。Password对应密码。Database上一步建的opc_iot。我强烈建议生产环境不要用root连接新建一个专用账号权限只给到该数据库的增删改查。这样可以避免误操作其他库也便于后期审计。创建语句如下CREATE USER opcwriter% IDENTIFIED BY 密码; GRANT SELECT, INSERT, UPDATE ON opc_iot.* TO opcwriter%; FLUSH PRIVILEGES;配置连接节点的名字建议直接写成MySQL-opc_iot节点多了以后好找。4.2 数据清洗函数的设计与实现OPC UA订阅输出的原始数据结构因为节点版本不同而有差异但通常都包含节点ID、值和时间戳。为了稳妥我习惯写一个Function节点把输出统一成下面这个结构{ tagName: Simulation_Random, tagValue: 12.345, quality: 192, sourceTime: 2024-01-06T10:01:02.123Z }函数内容如下按常见输出结构写的现场可以根据实际字段名调整var raw msg.payload; var nodeId raw.nodeId || msg.topic || unknown; var tagName nodeId.toString(); var tagValue null; var quality 0; var sourceTime null; if (typeof raw object) { // 常见情况value字段里带有实际值 if (raw.value ! undefined raw.value ! null) { tagValue raw.value.value ! undefined ? raw.value.value : raw.value; if (raw.value.sourceTimestamp) { sourceTime raw.value.sourceTimestamp; } } else if (raw.value null) { tagValue null; } else { tagValue raw; } if (raw.statusCode ! undefined) { quality raw.statusCode; } } else { tagValue raw; } // 时间戳缺失时用当前时间 if (!sourceTime) { sourceTime new Date().toISOString(); } // 去掉命名空间前缀只保留节点标识作为标签名方便数据库存储 tagName nodeId.replace(/^ns\d;(i|s)/, node_$1_); return { payload: { tagName: tagName, tagValue: tagValue, quality: quality, sourceTime: sourceTime } };注意一个处理逻辑tagName里我换掉了ns2;i1001这种带特殊字符的原始标识。虽然MySQL字段可以存这些字符串但后面在数据库里做查询、统计时用node_i_1001这种格式更顺手而且避免一些SQL拼接问题。写完函数之后拖一个switch节点做一下数据有效性过滤。比如服务器异常时可能推送状态码不等于Good质量码192这些数据如果直接入库会在报告里显示成负值或者异常值干扰分析。可以在switch节点里按质量码分桶Good的走正常落库分支其他质量码的走一个通知分支接调试节点或者写个日志表。4.3 MySQL写入节点的SQL配置与批量写入实践把清洗好的输出接到query节点的输入双击展开配置。在SQL标签页里输入insert语句。这里是动态参数需要用到node-red-contrib-mysql支持的问号占位符INSERT INTO tag_history (tag_name, tag_value, quality, source_time) VALUES (?, ?, ?, ?)然后在函数节点里payload需要配合成一个数组或者用params字段传参。我把函数节点最后输出的msg稍作调整msg.payload { tagName: tagName, tagValue: tagValue, quality: quality, sourceTime: sourceTime }; msg.params [ msg.payload.tagName, msg.payload.tagValue, msg.payload.quality, msg.payload.sourceTime ]; return msg;这样query节点会自动从msg.params里取参数填入SQL占位符。注意不要直接在SQL里拼字符串不但容易引入语法错误还有SQL注入风险虽然Node-RED这边没有外部用户输入但养成好习惯总没坏处。部署之后到数据库里查一下SELECT * FROM tag_history ORDER BY id DESC LIMIT 10;能看到数据一条条进来说明整条链路已经跑通了。接下来是优化单条INSERT在大数据量下效率太低。如果订阅了很多点位或者发布间隔很短建议用批量写入的方式。做法是先把若干条记录缓存到Node-RED的流变量里攒够比如20条再一次性拼成一条多值SQL。批量SQL的语句风格如下INSERT INTO tag_history (tag_name, tag_value, quality, source_time) VALUES (node_i_1001, 10.1, 192, 2024-01-06T10:01:02.000Z), (node_i_1002, 20.2, 192, 2024-01-06T10:01:02.000Z), ...在函数节点里可以把msg.params改成一个二维数组msg.params [ [node_i_1001, 10.1, 192, 2024-01-06T10:01:02.000Z], [node_i_1002, 20.2, 192, 2024-01-06T10:01:02.000Z] ];node-red-contrib-mysql节点会自动将二维数组批量提交。实测下来在单条INSERT写入大约1ms-2ms的场景下批量20条写入往往只需要3-5ms吞吐量提升三四倍CPU占用也低很多。我做批量缓存的方式是用一个单独的函数节点维护context里的数组buffer数据到达时push进数组数组长度达到阈值比如20把整个数组作为msg.params下发到query节点并清空buffer如果超时比如200ms还没有积满20条也要把已有数据先刷一次避免数据延迟过大这样即保证了吞吐又没有把延迟拉得太高。顺便说一句如果点位非常多比如几千个、每秒需要落库几千条记录那么MySQL的单表插入也会成为瓶颈。这个阶段再考虑时序数据库InfluxDB、TDengine或者分批落库方案但那是后话了先把基本链路跑通最重要。5. 常见问题与排查技巧实录5.1 OPC UA连接不上端点地址和网络问题这是我在社区里看到提问最多的一个问题。Node-RED的Client节点报类似Error: connect ECONNREFUSED说明TCP层就连不通。排查顺序如下先用Node-RED所在机器的命令行验证网络通不通ping OPCUA服务器IP。如果ping不通检查两台机器是否在同一网段、防火墙是否拦截。Windows的OPC UA服务器很多默认会监听动态端口如果你把Prosys装在带防火墙的Windows上第一次启动时记得允许Java或Prosys通过防火墙。如果ping通但连接还是失败用telnet或PowerShell测试端口Test-NetConnection 192.168.1.100 -Port 53530。端口通不了就查服务器端监听地址——Prosys默认监听0.0.0.0但KepwareEX的UA服务有可能只监听localhost需要在服务配置里改成所有接口。如果端口通但OPC UA握手失败比如报BadSecurityModeRejected那就是安全策略不匹配。把Client的安全策略改成None或者和服务端一致。一个特别容易忽略的坑OPC UA端点地址里的主机名部分。Prosys启动时会使用你自己的主机名比如opc.tcp://DESKTOP-ABC123:53530/opcua/server但你的电脑可能无法解析这个主机名。解决办法是直接用IP地址opc.tcp://192.168.1.100:53530/opcua/server。5.2 数据读到了但库表没写入SQL和参数问题这类问题调试面板通常不会直接报错而是显示transferred: 0或者没有任何反馈。排查手段先在query节点前面加一个debug节点确认进入query节点的msg里params字段是否是预期格式。数组长度、参数个数和SQL占位符是否一致少一个占位符MySQL会报错多一个也会报错。检查query节点的输出把执行结果都接一个debug节点。node-red-contrib-mysql在执行成功后会返回一个包含affectedRows的payload如果affectedRows为0多半是SQL语法问题或者值是NULL导致插入条件不成立。常见的SQL错误还有字段名不对、表名拼错、字符串值少引号。如果用了反引号包裹字段名注意是反引号不是单引号。如果你的时间戳字段是DATETIME类型插入的字符串格式需要匹配。MySQL的source_time字段如果用ISO8601格式如2024-01-06T10:01:02.000Z能自动转换但如果时区差8小时记得在连接字符串里调整时区设置或者干脆用MySQL函数在SQL里转换STR_TO_DATE(?, %Y-%m-%dT%H:%i:%s.%fZ)。这类能读不能写的排查核心思路就是分两段先验证SQL本身能否用Navicat手工执行成功再把参数逐步代入看是哪一环破坏格式。5.3 部署后运行一段时间节点掉线不重连OPC UA订阅在长时间运行后有可能因为网络抖动、服务器端重启、证书过期等原因断开导致整个流看起来还在运行但数据已经不再更新。Node-RED的订阅节点一般有自动重连机制但我在几个项目里发现它并不总是可靠。解决方案我在生产环境里给Subscription节点配了一个简单的看门狗在Subscription节点后面接一个函数节点检查msg的时间戳sourceTimestamp或serverTimestamp。如果距离当前时间超过阈值比如发布间隔的3倍以上就认为订阅已经挂掉。在Node-RED里设置一个定时器inject节点周期5秒定期检查这段数据流中最近一次数据到达时间。如果发现数据超时未更新就调用Client节点的一个特殊能力重连——最简单的方式是在Node-RED里用context标记一段需要清空重连的连接然后让Client节点的connected事件触发重新初始化。更稳妥一点的做法是给Subcription节点加一个heartbeat点位如果OPC UA服务器允许在订阅里额外加上一个服务器自身的周期计数器节点很多服务器自带比如Prosys的ns2;i1只要这个值还在变化就说明订阅链路活着如果连它都不动了说明连接已经断开这时用node.send发一个重置信号到Client节点的reset端口强制重建连接。这个看门狗机制在我的现场项目里非常管用。用了它之后连续运行数月不掉链子哪怕中间对端的服务器升级重启过也能在几十秒内自愈。5.4 中文乱码和时区问题老生常谈但总踩坑数据库编码在五年前还是utf8够用现在必须用utf8mb4。采集的数据里如果包含中文标签名或注释字段用utf8有时候会报Incorrect string value错误。所以建库和建表时我都用utf8mb4注意不是只在建库时指定连接串里也要用characterEncodingutf8mb4如果是JDBC连接或charsetutf8mb4Node-RED的mysql连接。Node-RED的mysql节点默认走的连接协议字符集可以在MySQL配置里用character-set-server统一指定所以我在MySQL的my.ini里每次都写死utf8mb4。时区问题是另一类高频坑。OPC UA推送的时间戳通常是UTCISO8601格式结尾带Z而MySQL本地的CURRENT_TIMESTAMP和你的系统时区有关。如果你发现source_time比实际时间慢了8小时那是UTC和北京时间UTC8的差异。我建议在Node-RED函数节点里统一把时间戳转成本地时区var d new Date(raw.sourceTimestamp); sourceTime d.toISOString(); // 存UTC数据库里source_time字段存UTCrecord_time字段用MySQL的CURRENT_TIMESTAMP存本地时间。这样两个字段一个对应设备端UTC一个对应服务器本地时间调试时一目了然不会混乱。5.5 点位数量多、发布间隔短的性能优化建议如果订阅数百上千个点位发布间隔设置到100ms每两秒就攒了几千条记录要落库MySQL压力会很大。我实测过单台普通配置服务器上MySQL单表每秒插入几千条一般能顶住但CPU占用和磁盘IO会明显上去。这时候有几招降低落库频率发布间隔从100ms调到500ms或1s大多数历史分析场景根本不需要毫秒级数据。批量写入上面的批量SQL方案把单条INSERT改成多值批量。分区表按月、按天做MySQL分区查询时按时间范围过滤更快但写入性能没太大提升适合查询优化。引入缓存层如果数据量实在太大先写到Redis周期性地批量刷到MySQL但这会引入额外的架构复杂度小项目一般用不到。先做好2再考虑4不要一上来就把架构搞复杂。6. 库表设计与运维层面的几条建议6.1 点位映射表和标签元数据管理如果现场只有三五个点位直接在采集表里写死tag_name就行。但当点位数量多起来我会建一张维度表做点位元数据管理结构类似CREATE TABLE tag_meta ( id INT AUTO_INCREMENT PRIMARY KEY, tag_key VARCHAR(128) UNIQUE NOT NULL COMMENT Node-RED里的点位标识, tag_display_name VARCHAR(128) NOT NULL COMMENT 中文名称, unit VARCHAR(32) NULL COMMENT 工程单位, description VARCHAR(255) NULL COMMENT 描述, enabled TINYINT DEFAULT 1 COMMENT 是否参与采集 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;点位的业务信息——比如一号炉温度单位℃——不需要在每一条历史数据里都重复存储放在tag_meta里维护一次就行。查询时用JOIN关联tag_meta和tag_history报表里展示的就是业务名称和单位而不是一串node_i_1001的代码。尤其在给非技术的车间同事做报表时这个表的意义非常大。Node-RED侧可以定时比如每小时从tag_meta表读一次启用状态动态决定订阅哪些节点省得每次增删点位都要改流并重新部署。6.2 数据保留策略与定期清理历史日志表最大的特点就是只增不减时间长了磁盘空间迟早报警。我建议在表设计阶段就规划保留策略比如保留90天原始数据超过90天的按小时聚合后删除。MySQL没有内建的TTL功能写一个简单的存储过程或者Node-RED定时任务每天晚上清理过期数据DELETE FROM tag_history WHERE record_time NOW() - INTERVAL 90 DAY LIMIT 10000;加LIMIT是为了避免一条大事务锁表太久影响业务写入分批清理更温和。如果数据量真的很大直接在MySQL里定期DELETE可能性能不好更建议换用分区表按天分区删除旧数据就变成一个ALTER TABLE tag_history DROP PARTITION p20241001的操作秒级完成。6.3 用定时任务重算前一天数据质量最后再分享一个我曾经做过的扩展思路在Node-RED里加一个定时任务每天凌晨跑一次汇总查询生成前一天的日报表比如每个点位一天内的最大值、最小值、平均值、超限次数。这个表可以在MySQL里预创建Node-RED每天生成一次汇总结果写进去这样车间看板直接查汇总表就行不用每次现算几百万条原始数据。实现起来不复杂一个inject节点设置成cron触发Node-RED 2.x支持注入定时调度后面接query节点执行聚合SQL再把结果写入汇总表。整个任务就是一条流不需要额外的定时任务框架。这个思路扩展性很好——你今天能汇总日报后续做周报、月报、设备利用率统计都是在同一套架构上多加几个定时任务而已。我自己实际运维这套方案时最大的体会是Node-RED最大的价值不是能跑通而是好维护、好扩展。同样是OPC UA数据采集用C#写一套程序从编码到调试可能要两三天还要考虑编译、部署、配置文件格式。Node-RED这边半小时跑通管道后续改一个点位、加一个联动逻辑界面上几分钟搞定非开发背景的同事也能上手。这就是它在工业小场景里受欢迎的根本原因。还有一个让我印象深刻的经验做数据采集一定要把质量码和时间戳当做一等公民来对待不要只盯着值。工业现场的数据不是所有时刻都可靠设备断电、传感器故障、通信抖动都会产生质量略低的数据。如果你把质量码完整存下来了后面做分析、做告警时能省很多事如果当初为了省空间丢掉了等遇到数据莫名其妙多了一个尖峰而你没法溯源时就悔之晚矣。整套方案跑通之后可以继续往这些方向扩展OPC UA数据转MQTT上云、Node-RED里做简单的阈值告警并推送到微信或钉钉、接入InfluxDB做时序分析、或者对接大屏可视化。数据底座已经打在MySQL里了上层怎么玩都行。
返回列表