工业边缘计算实战:基于Node-RED与Modbus TCP的数据采集与可视化 1. 项目概述当工业边缘计算遇上可视化编程最近在折腾一个工业数据采集与监控的小项目核心是把现场一堆不同品牌、不同协议的PLC和传感器数据统一采集上来做点简单的逻辑处理和可视化。硬件平台选用了倍福Beckhoff的Edge Box RPi 200软件栈则打算用Node-RED来搭桥。为什么这么选因为Edge Box RPi 200本质上是一个基于树莓派CM4的工业级边缘控制器它提供了标准的工业接口和坚固的外壳可以直接扔在现场的电气柜里环境适应性比普通的工控机或自己组装的树莓派强太多了。而Node-RED这个基于流的低代码编程工具简直是快速构建物联网应用的“瑞士军刀”用拖拽节点的方式就能把数据流串起来特别适合做协议转换、数据预处理和简单的控制逻辑。这个项目的核心挑战在于现场的设备通信协议五花八门其中Modbus TCP又是工业领域最通用、最开放的协议之一。我的目标就是让Edge Box RPi 200通过Node-RED稳定、高效地与支持Modbus TCP的从站设备比如PLC、智能电表、温控器进行通信把数据读上来再根据业务需求进行处理和转发。这听起来像是工业互联网或工业4.0里一个非常基础的场景但真要把每一步都走通、走稳里面有不少细节需要抠。比如Modbus TCP的寄存器地址映射、数据类型的解析、通信超时和重连机制以及在Node-RED里如何优雅地组织流都是实打实的经验。接下来我就把这个从硬件上电到数据流畅读取的全过程结合踩过的坑和总结的技巧详细拆解一遍。2. 硬件平台与软件栈选型解析2.1 为什么是Edge Box RPi 200在选择硬件时我对比过传统的工控机、普通的树莓派加扩展板以及倍福的这款边缘设备。最终锁定Edge Box RPi 200主要是基于以下几个硬核考量工业级可靠性是首要因素。普通的树莓派虽然便宜灵活但它的设计初衷是教育和创客PCB板裸露接口非加固抗电磁干扰EMI能力弱长时间在工厂的电气柜里运行很容易因为振动、粉尘、温湿度变化或者电网波动而出问题。Edge Box RPi 200则完全不同它采用了金属外壳提供了IP20的防护等级接口都是坚固的弹簧端子或M12连接器电源输入范围宽12-28 V DC并且通过了相关的工业EMC测试。这意味着它可以被直接安装在DIN导轨上与断路器、继电器、PLC模块并肩工作环境适应性不是一个量级。性能与接口的平衡。它核心是树莓派Compute Module 4我选的是4GB内存的版本性能对于运行一个轻量级的Linux系统、Node-RED以及一些Python脚本绰绰有余。关键是其板载的接口非常“工业”两个千兆以太网口这对于区分管理网络和设备网络非常有用、两个USB 2.0主机端口、一个Micro HDMI以及最重要的——两个RS485接口和一个RS232接口。RS485是Modbus RTU等现场总线协议的物理层基础虽然我这个项目主要用Modbus TCP走网口但多出来的串口为未来接入更老的设备留足了余地。这种开箱即用的接口配置省去了额外购买和配置USB转串口模块的麻烦和潜在的不稳定性。官方软件支持与生态。倍福为其Edge设备系列提供了TcRuntime这是一个基于Debian的实时Linux系统。虽然在这个项目里我为了更灵活地使用Docker和最新版的Node-RED选择了安装标准的Raspberry Pi OS64位但倍福官方对树莓派CM4的硬件支持是到位的驱动完善。而且作为一家资深的工业自动化厂商其硬件在设计时对工业通信的实时性和稳定性有更深层的考量这是纯消费级硬件无法比拟的。2.2 Node-RED快速原型与生产部署的利器Node-RED在这个项目中扮演着“中央调度器”和“粘合剂”的角色。它的优势在于极低的入门门槛和极高的开发效率。可视化编程降低复杂度。对于不擅长传统文本编程的工程师来说通过拖拽“节点”Node并用“连线”Wire将它们连接起来形成“流”Flow这种图形化的方式非常直观地展现了数据流向和处理逻辑。例如一个完整的Modbus TCP读取流程可以这样构建一个定时触发器节点 - 一个Modbus Read节点 - 一个函数节点用于数据解析 - 一个仪表盘节点用于显示。整个过程不需要写一行通信底层的代码。丰富的节点库生态。Node-RED拥有一个由社区贡献的庞大节点库Palette。对于工业协议除了官方的node-red-contrib-modbus节点包功能非常强大支持Modbus TCP和RTU还有针对OPC UA、MQTT、西门子S7协议等的众多节点。这意味着你可以用同一种编程范式去集成各种异构系统。node-red-dashboard节点包则能让你快速搭建一个本地化的Web监控界面虽然比不上专业的SCADA系统华丽但对于快速验证和中小型监控场景完全够用。轻量且易于部署。Node-RED本身是Node.js应用资源占用小。在Edge Box RPi 200上我可以直接通过apt安装或者更推荐使用Docker容器化部署。容器化能将Node-RED及其依赖的环境打包迁移和升级都非常方便。一旦流设计调试完成整个应用就固化下来了运行稳定非常适合边缘侧长期运行。2.3 Modbus TCP工业通信的通用语言Modbus协议家族在工业领域有着近乎垄断的地位而Modbus TCP是其基于以太网TCP/IP的变种。选择它作为主要通信协议原因很直接开放与简单。Modbus协议标准是公开的没有授权费用。其协议本身也非常简单本质上就是一个“问答”模型主站本例中就是我们的Node-RED发送一个包含从站地址、功能码、寄存器地址、数据长度的请求帧从站现场的PLC等回复一个包含数据或执行状态的响应帧。这种简单性带来了极高的可靠性和广泛的设备支持。与现场设备无缝对接。目前市面上绝大多数PLC、HMI、变频器、智能仪表都支持Modbus TCP作为标准通信接口之一。这意味着我们这套基于Edge Box RPi 200和Node-RED的方案具备了与海量现有设备对话的能力项目通用性极强。需要厘清的关键概念很多人刚开始接触Modbus时会对“寄存器地址”感到困惑。这里有个关键点协议地址 vs. 设备标签地址。Modbus协议定义的寄存器地址是从0开始的。例如功能码03读保持寄存器请求读取地址为0的寄存器对应的是设备的40001地址这是一种常见的表示法即在寄存器地址上加40001。但有些设备的编程软件或手册里直接使用“40001”这样的标签地址。在配置Node-RED的Modbus节点时必须使用协议地址即0-65535。如果设备手册上写的是“保持寄存器40001-40010”那么在节点里应该配置的起始地址就是0数量是10。混淆这一点是导致读不到数据的常见原因。3. 系统环境搭建与核心配置3.1 为Edge Box RPi 200安装操作系统Edge Box RPi 200的CM4核心板默认没有存储需要插入一张MicroSD卡作为系统盘。我推荐使用Raspberry Pi OS Lite (64-bit)这个版本。它没有图形桌面资源占用更少更适合无头Headless运行的边缘设备。下载与烧录从树莓派官网下载镜像使用BalenaEtcher或Raspberry Pi Imager工具将镜像烧录到SD卡建议至少16GBClass 10以上速度。预配置网络与SSH关键步骤在烧录完成后不要急着拔卡。在电脑上挂载SD卡的boot分区在Windows下就是一个可读的盘符。在该分区根目录下新建一个名为ssh的空白文件无后缀这将在首次启动时启用SSH服务。接着新建一个名为userconf.txt的文件内容为用户名:加密后的密码。你可以用命令echo mypassword | openssl passwd -6 -stdin生成加密密码然后将用户名:加密串写入文件。这样就能实现免交互首次登录。首次启动与基础配置将SD卡插入Edge Box上电。通过路由器管理界面或扫描工具如Advanced IP Scanner找到设备的IP地址。使用SSH客户端如PuTTY连接。首次登录后立即执行sudo raspi-config进行基础设置修改密码虽然预配置了但最好改一下。本地化选项设置时区Asia/Shanghai配置键盘布局通常不需要改。高级选项扩展文件系统将整个SD卡空间分配给系统。网络选项如果需要可以在这里设置静态IP。我更推荐在路由器上做DHCP静态绑定这样管理更集中。系统更新与必要工具安装sudo apt update sudo apt upgrade -y sudo apt install -y vim git curl wget net-tools注意工业现场的网络环境可能不允许设备访问外部互联网进行apt update。在这种情况下你有两个选择一是在办公室网络环境下完成所有软件的安装和更新再将设备部署到现场二是在现场搭建一个本地Debian软件源镜像。前者更简单常用。3.2 安装与配置Node-RED我将采用Docker方式来安装Node-RED。这能保证环境隔离且备份、迁移、升级都极其方便。安装Docker Engine使用官方提供的一键安装脚本是最快的方式。curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker $USER执行完最后一条命令后你需要注销SSH会话并重新登录才能使当前用户加入docker用户组生效之后运行docker命令就不需要每次都加sudo了。创建Node-RED的数据持久化目录Docker容器默认是无状态的重启后数据会丢失。我们必须将Node-RED的流数据、节点配置、以及后续安装的节点包映射到宿主机的磁盘上。mkdir -p ~/node-red/data这个~/node-red/data目录将用来保存一切需要持久化的东西。使用Docker Compose部署Node-RED推荐编写一个docker-compose.yml文件能让服务管理更清晰。首先安装Docker Composesudo apt install -y docker-compose然后在用户目录下创建docker-compose.ymlversion: 3.8 services: node-red: image: nodered/node-red:latest-minimal container_name: node-red restart: unless-stopped ports: - 1880:1880 environment: - TZAsia/Shanghai volumes: - ./node-red/data:/data # 如果需要在容器内访问宿主机的串口或特定网络可能需要以下配置 # devices: # - /dev/ttyUSB0:/dev/ttyUSB0 # network_mode: host这里有几个关键点image: nodered/node-red:latest-minimal使用minimal标签的镜像它比完整版更小巧适合资源有限的边缘设备。restart: unless-stopped确保容器在异常退出或系统重启后能自动启动这是生产环境必备设置。volumes将宿主机的./node-red/data目录挂载到容器的/data路径实现数据持久化。TZ设置容器内时区保证日志和时间相关功能正确。启动服务docker-compose up -d-d参数表示后台运行。启动后在浏览器访问http://你的Edge Box IP:1880就能看到Node-RED的流程图编辑器界面了。3.3 安装Modbus节点并配置连接Node-RED默认没有Modbus节点需要从“节点管理”中安装。安装Modbus节点包在Node-RED编辑器界面点击右上角菜单 - “节点管理” - “控制面板” - “安装”。在搜索框中输入node-red-contrib-modbus找到由biancode维护的版本这是目前最活跃、功能最全的Modbus节点包点击安装。安装过程可能需要几分钟因为它会下载依赖。理解Modbus节点的结构安装完成后左侧节点面板的“网络”分类下会出现一系列Modbus节点。最重要的两个是“Modbus Read”和“Modbus Write”。但在使用它们之前你需要先配置一个“Modbus Flex Getter”或直接在读写节点中配置连接。我更喜欢使用“Modbus Flex Getter”作为连接配置中心因为它可以统一管理串口或TCP连接参数并被多个读写节点复用。配置Modbus TCP连接从左侧拖拽一个“Modbus Flex Getter”节点到工作区双击它进行配置。Connection Type:选择Modbus TCP。Host/IP Address:填写你的Modbus从站设备例如PLC的IP地址如192.168.1.100。Port:默认为502绝大多数Modbus TCP设备都使用这个端口。Unit ID:这是Modbus从站地址Slave ID。在Modbus TCP中这个字段通常被包含在协议数据单元PDU中用于在网关后区分多个RTU设备或者直接作为设备标识。需要根据你的从站设备手册填写常见的是1。其他高级选项Reconnect Timeout:设置为5000(毫秒)。当连接断开时节点会尝试重连。Queue Timeout:设置为10000。这是请求排队等待响应的最长时间。给这个配置节点起一个有意义的名字比如PLC_Modbus_TCP_Config然后点击“完成”。实操心得在工业现场网络不一定稳定。务必合理设置Reconnect Timeout和Queue Timeout。时间太短可能导致在短暂的网络抖动下频繁重连影响效率时间太长则会导致系统对故障反应迟钝。通常5-10秒的重连超时和10-30秒的队列超时是比较折中的选择。你可以在后续的“状态”节点中监控连接状态。4. 构建数据读取流从寄存器到可视化4.1 设计一个基础的读取流程现在我们来构建一个最简单的数据读取流周期性地从PLC读取一组保持寄存器Holding Register的值。添加触发节点拖拽一个“inject”节点到工作区。它用于手动触发或定时触发流。双击配置将“重复”选项设置为“间隔”比如每5秒一次。Payload类型选择“字符串”内容可以留空或写个提示。这个节点就是我们的“心跳”或“定时器”。添加读取节点拖拽一个“Modbus Read”节点到工作区放在inject节点右边。双击配置。Server:选择刚才创建的PLC_Modbus_TCP_Config。FC:选择3 - Read Holding Registers。这是最常用的功能码读取可读写的寄存器。Address:这里填协议地址。假设我们要读取设备手册上标注的“40001”到“40005”这5个寄存器那么地址就填0。Quantity:填5。Poll Rate:留空。因为我们用inject节点来触发这里就不需要节点自身的轮询了。如果这里设置了Poll Rate它就会按照自己的节奏读可能会和inject冲突。Use Polling:取消勾选。因为我们使用外部触发。Show Status:勾选。这样节点在流程图上会显示最后通信的状态成功/失败。添加调试节点拖拽一个“debug”节点到工作区连接到Modbus Read节点的输出。双击debug节点将输出设置为“完整消息对象”。这样我们能看到Node-RED收到的所有原始数据。连线与部署将inject节点的输出连接到Modbus Read节点的输入。点击右上角的红色“部署”按钮。部署成功后点击inject节点左侧的按钮手动触发一次或者在等待5秒后查看右侧的调试面板。你应该能看到一个msg.payload对象里面包含一个数组数组里的5个数字就是从寄存器0-4读上来的值。4.2 解析复杂数据类型Modbus寄存器每个通常是16位2字节的无符号整数0-65535。但实际工程中我们需要的数据类型多种多样32位浮点数Float、32位有符号整数DINT、甚至字符串String。这些数据需要占用连续的多个寄存器并按特定的字节顺序Byte Order组合解析。常见的数据类型与寄存器占用数据类型占用寄存器数量说明UINT16 (WORD)116位无符号整数直接读取即可INT16116位有符号整数需判断最高位UINT32 (DWORD)232位无符号整数涉及高低字/字节顺序INT32 (DINT)232位有符号整数涉及高低字/字节顺序FLOAT32 (REAL)2单精度浮点数涉及高低字/字节顺序使用“函数”节点进行解析Modbus Read节点输出的msg.payload是一个寄存器值数组。我们需要一个“函数”节点来编写JavaScript代码进行解析。在Modbus Read节点后添加一个“function”节点。双击打开输入解析代码。例如假设我们从地址0开始连续读取了2个寄存器值分别为reg0和reg1设备手册说明这两个寄存器共同组成一个32位浮点数且字节顺序为“ABCD”即高字在前高字节在前也称为“大端序”或“Modbus顺序”。解析代码如下// 假设msg.payload [高字, 低字]例如 [16286, 37479] let registers msg.payload; if (registers.length 2) { // 将两个16位寄存器值合并为一个32位整数 // 注意JavaScript位操作是32位有符号的所以这里用乘法更安全 let combined (registers[0] 16) | registers[1]; // 创建一个ArrayBuffer和DataView来解析IEEE 754浮点数 let buffer new ArrayBuffer(4); let view new DataView(buffer); // 按照ABCD顺序大端序设置字节 view.setUint16(0, registers[0], false); // false 表示大端序 view.setUint16(2, registers[1], false); // 读取为32位浮点数 let floatValue view.getFloat32(0, false); // 将结果赋值给新的payload方便后续节点使用 msg.payload { rawRegisters: registers, floatValue: floatValue, // 可以顺便做个单位转换或格式化 displayValue: floatValue.toFixed(2) °C // 假设是温度值 }; } else { msg.payload { error: Not enough registers read }; } return msg;将Modbus Read节点的输出连接到这个函数节点再将函数节点的输出连接到debug节点。部署后触发你就能在debug面板看到解析后的浮点数值了。核心技巧字节序Endianness是最大的坑不同厂商、不同型号的PLC对多字数据的存储顺序可能不同。常见的顺序有ABCD (Big-Endian):高字在前高字节在前。这是Modbus标准推荐顺序也是node-red-contrib-modbus节点默认处理的顺序。BADC (Big-Endian Byte Swap):高字在前但高低字节交换。CDAB (Little-Endian):低字在前但高低字节不交换。DCBA (Little-Endian Byte Swap):低字在前高低字节交换。 如果解析出来的浮点数是一堆毫无意义的极大或极小的数字如1.5E-43或者明显不对首要怀疑对象就是字节序搞错了。你需要查阅设备通信手册找到确切的字节顺序并调整DataView中setUint16和getFloat32的偏移量和端序参数true表示小端序。4.3 构建可视化仪表盘数据解析出来后我们可以用node-red-dashboard节点包快速创建一个本地Web监控界面。安装Dashboard节点在节点管理面板中搜索安装node-red-dashboard。创建UI组态安装后左侧会出现“dashboard”分类。首先拖拽一个“tab”节点和“group”节点到工作区进行布局规划。Tab代表页面标签Group是标签页内的分组。添加显示部件将解析完数据的函数节点输出连接到一个“gauge”仪表节点或“chart”图表节点。双击仪表节点进行配置Group:选择你创建的UI分组。Label:写上名称如“温度”。Value Format:选择{{msg.payload.floatValue}}或{{msg.payload.displayValue}}这取决于你想显示函数节点输出的哪个字段。Dashboard节点使用AngularJS表达式来访问msg对象的属性。Range:设置仪表的量程如0-100。部署并访问面板部署流之后除了编辑器地址1880端口Node-RED Dashboard还会自动启用一个UI界面默认在1880/ui。在浏览器中打开http://Edge Box IP:1880/ui你就能看到实时更新的仪表盘了。5. 高级应用与稳定性优化5.1 实现读写混合与逻辑控制一个完整的监控系统不仅要读还要能写。例如根据读取的温度值自动控制一个风扇的启停通过写一个线圈Coil。创建写操作流新增一个流或者在同一流中添加分支。用一个“switch”节点来判断温度。例如当温度函数节点解析出的msg.payload.floatValue 30时输出到1端口。配置Modbus Write节点将一个“Modbus Write”节点连接到switch节点的输出端口。双击配置Server:选择同一个Modbus TCP配置。FC:选择5 - Write Single Coil写单个线圈或15 - Write Multiple Coils。Address:线圈的协议地址。例如设备手册上线圈“00001”对应的协议地址是0。Value:可以设置为固定值true启动或通过msg.payload传递。为了灵活通常在switch节点后接一个“change”节点将msg.payload设置为需要的布尔值或数值再传给Write节点。状态反馈与互锁写操作后最好能再读取一次该线圈的状态确认动作已执行。可以触发一个延迟的Modbus Read来验证。对于重要的控制命令还应加入软件互锁或硬件互锁逻辑防止误操作。在Node-RED中可以用“trigger”节点来生成单脉冲信号避免因传感器抖动导致写命令被重复执行。5.2 错误处理与通信稳定性加固工业现场网络环境恶劣通信中断是常态而非异常。我们的流必须具备鲁棒性。利用Modbus节点的状态输出Modbus Read/Write节点下方有一个灰色小点代表状态输出。将其连接到一个“status”节点可以实时获取通信状态如“连接中”、“已连接”、“错误”。我们可以根据状态来触发报警或切换备用通信路径。实现心跳与超时重试除了周期性的数据读取可以专门建立一个“心跳”流以更短的间隔如每秒读取一个固定的、无害的寄存器。通过监控这个心跳流的响应成功率和延迟来判断网络质量。如果连续多次失败可以触发一个“重连”函数甚至通过“exec”节点调用系统命令重启网络接口。队列管理与防拥塞不要无节制地高速轮询所有数据。过多的并发请求会压垮从站设备特别是低端PLC或导致网络拥堵。合理规划轮询周期将不同紧急程度的数据分配到不同的时间间隔如关键工艺参数1秒一般状态参数5秒产量统计30秒。可以使用Node-RED的“delay”节点来限制速率或者用“queue”节点来管理并发请求。数据缓存与断线续传在关键数据流后接入一个“file”节点将数据以追加模式写入到Edge Box的本地文件中例如CSV格式。这样即使网络完全中断导致数据无法上传到云端本地也有备份。网络恢复后可以用另一个流读取本地文件补传数据。5.3 与上层系统集成Edge Box RPi 200作为边缘网关其价值在于承上启下。除了本地处理和可视化更重要的是将处理后的数据上报。通过MQTT上报到云平台或SCADA安装node-red-contrib-aedes或使用标准的mqtt out节点。在数据解析函数节点后将格式化好的数据如{temperature: 25.6, unit: C}作为payload通过MQTT节点发布到指定的主题如factory/line1/temperature。云端的MQTT Broker如EMQX, HiveMQ或直接支持MQTT的SCADA系统如Ignition就可以订阅并存储、展示这些数据。通过HTTP/HTTPS API推送使用“http request”节点将数据以JSON格式POST到指定的服务器API接口。这种方式适合与私有部署的数据中台或定制化系统对接。写入本地或远程数据库使用node-red-node-sqlite节点可以将数据写入Edge Box本地的SQLite数据库轻量且零配置。如果需要写入远程MySQL、PostgreSQL或时序数据库InfluxDB也有相应的节点包可用。这为后续在边缘侧进行更复杂的数据分析提供了可能。6. 常见问题排查与调试心得在实际部署中你一定会遇到各种问题。下面是一个快速排查清单现象可能原因排查步骤Modbus节点显示“连接错误”或“超时”1. 网络不通2. IP或端口错误3. 从站设备未上电或故障4. 防火墙阻拦1. 在Edge Box上用ping 设备IP测试网络连通性。2. 使用telnet 设备IP 502或nc -zv 设备IP 502测试502端口是否开放。3. 检查从站设备状态指示灯。4. 检查从站设备或中间交换机的防火墙设置。能连接但读回的数据全是0或655351.寄存器地址错误最常见2. Unit ID (Slave ID) 错误3. 功能码(FC)选择错误1.反复确认协议地址用设备本身的编程软件如TIA Portal、GX Works在线监控看你想读的变量实际映射到了哪个Modbus地址。这是最权威的方法。2. 核对设备手册中的从站地址。3. 确认是读保持寄存器(03)还是读输入寄存器(04)。读回的数据是乱码或完全不对1.字节序(Endianness)错误2. 数据类型解析错误3. 寄存器数量不对1. 尝试更换字节序组合ABCD, BADC, CDAB, DCBA进行解析测试。2. 确认设备手册中该数据区的确切数据类型32位浮点32位整数。3. 确认读取的寄存器数量是否足够覆盖整个数据如浮点数需要2个。Node-RED Dashboard无法访问1. Dashboard节点未正确部署2. 防火墙阻止了1880端口3. UI地址错误1. 点击部署按钮确保无错误。2. 检查Edge Box的防火墙规则sudo ufw status。3. 确认访问地址是http://IP:1880/ui而非http://IP:1880。通信间歇性失败时好时坏1. 网络干扰或负载过高2. 从站设备处理能力不足3. 轮询频率过快1. 检查网线、交换机。尝试ping大包测试是否有丢包ping -s 1472 设备IP。2. 降低轮询频率增加轮询间隔。3. 在Modbus配置中增加Queue Timeout和Reconnect Timeout。写入命令不生效1. 写入地址被写保护2. 写入值格式不正确3. 从站处于非运行模式1. 检查从站设备中该地址的读写权限设置。2. 确认写入节点配置的FC和数据类型写线圈是布尔值写寄存器是整数。3. 确认PLC处于RUN模式。我个人在调试中最深刻的体会是善用工具。在将Node-RED流部署到Edge Box之前我强烈建议先在电脑上使用Modbus Poll或Modbus Slave模拟从站这类专业调试软件进行测试。用这些软件可以100%确定你的Modbus主站请求帧是否正确以及从站的响应帧是什么。这能帮你快速隔离问题是出在Node-RED配置上还是出在网络或从站设备本身。当你在Modbus Poll里能稳定读到数据后再把完全相同的参数IP、端口、Unit ID、地址、功能码搬到Node-RED里配置成功率会高得多。另外Node-RED编辑器自带的调试面板信息非常丰富一定要学会看msg对象的完整结构里面常常包含了错误码和详细描述是定位问题的第一手资料。最后对于长期运行的系统一定要把关键的日志尤其是错误日志通过“file”节点记录下来这是日后排查偶发性问题的唯一依据。