尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

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

基于Java的IEC 104主站客户端设计与微电网监控实现

基于Java的IEC 104主站客户端设计与微电网监控实现 简介本资源是一款基于IEC104协议的微电网管理系统主站客户端程序面向电力系统自动化工程师、智能电网开发人员及高校电力信息化方向学习者解决微电网远程监控、实时数据采集与设备控制等核心工程问题。程序采用Java实现集成多线程Socket通信机制保障高实时性遥信遥测解析支持遥控遥调命令下发并通过高并发数据库操作应对海量测点数据的快速读写需求。压缩包共107个文件含23个核心Java源码、30个编译后class文件、9个依赖jar包、22个界面资源png、10个配置json及4个properties文件结构完整便于二次开发与协议调试整体大小3.62MB轻量实用。已有141人下载学习配套提供项目配置说明、DAO层数据访问示例如PVDigitalQuantityDataDao、DevControlDao、ASDU报文解析类Asdu.class及客户端多线程回调逻辑Client$2.class、Client$3.class可直接用于IEC104通信对接与微电网主站功能验证。 老规矩先交代一下背景。微电网管理系统这东西核心就是要把分散在园区、台区、厂房屋顶上的光伏、储能、充电桩、并网柜全部拉到一个平台上来看。之前我接手的一个项目现场已经有一套用Modbus RTU硬拉的方案只覆盖到逆变器和电表储能PCS和并网开关的状态根本拿不上来遥控更不敢做。后来甲方提了一个硬性要求必须走IEC 104规约对接地方调度和区域监控同时主站侧得自己做一套数据采集与监控系统。于是就有了这个基于Java的IEC 104主站客户端项目。给各位准备搞电力信息化、微电网监控、或者想理解工业规约怎么落地成代码的朋友一句话总结本文就是把这套程序的通信链路、报文解析、命令下发、高并发存储这些核心模块从设计思路到实际代码怎么写的一层层剥开来讲清楚。内容不深奥但都是现场踩坑踩出来的经验。1. 项目整体设计与思路拆解1.1 为什么微电网管理系统要选IEC 104先解决一个基本问题为什么是IEC 104而不是Modbus、MQTT或者其他物联网协议说实话Modbus在微电网内部的设备级通信里非常常见逆变器、电表、温控器基本都支持Modbus RTU/TCP。但Modbus有一个致命短板它的应用层没有标准的对象模型。你想表达一个开关的合位、一个PCS的远程停机指令都需要自己映射寄存器地址而且没有品质描述、没有时标、没有时间同步机制、没有召唤传输机制。在多设备、大点位比如超过5000个遥信/遥测点的场景下Modbus的点表维护就是一场灾难。IEC 104解决的就是这个问题。它脱胎于IEC 870-5-101规约是电力系统调度自动化的国际标准国内电网规约也是基于它做的扩展。它对遥信、遥测、遥控、遥调的报文结构、传输规则、超时机制、控制方向的过程都做了非常详细的定义。最关键的一点是IEC 104是 主站-子站 模型天然适配调度中心往下采集、往下控制的场景。所以这个项目的定位就很清晰了整套程序作为主站Master/Controlling Station通过以太网连接各个子站即微电网中的测控装置、规约转换器、PCS、并网开关控制器完成数据的实时采集和反向控制。1.2 主站客户端的核心职责边界很多人以为做一个IEC 104客户端就是把报文拼出来发出去这是一个很明显的误区。做过现场的人才明白一个合格的主站客户端至少要承担这五个层面的职责链路管理负责TCP连接的生命周期包括连接建立、链路启动STARTDT、链路测试TESTFR、超时重连。子站挂了你要知道子站恢复了你要能自动恢复数据传输。会话同步IEC 104规定了一组U帧U格式报文握手流程主站必须正确发送STARTDT act并等待STARTDT con否则子站不会上报任何数据。这一点很多人第一次做的时候容易漏。报文解析与数据交换把收到的I帧和S帧报文拆成ASDU应用服务数据单元解析出遥信单点/双点信息、遥测标度化值、短浮点数、长浮点数、电度、SOE带时标的事件记录等同时把解析后的数据交给上层业务。命令下发与执行反馈遥控单点命令C_SC_NA_1、双点命令C_DC_NA_1和遥调设点命令C_SE_NC_1、C_SE_NB_1有严格的执行流程下发选择Select- 等待确认 - 下发执行Execute——这叫选择-执行机制防止误动。命令执行结果还需要通过监视方向的确认报文ACTTERM反馈回来。数据落库主站系统不只是看一眼数据还得把采集到的海量测点数据持久化到数据库供历史曲线、数据分析、报表用。数据的频率如果按秒级入库需要设计合理的缓冲和批量写入机制不然数据库会被写爆。1.3 技术选型与整体架构方案技术栈上我选择的是Java 8以上环境、原生Socket多线程通信、MySQL或者根据现场情况用PostgreSQL HikariCP连接池 MyBatis或Spring JDBC。不引入Netty的主要原因有两点一是IEC 104主站连接数并不会特别大单机房可能就几十个子站BIO模型足够二是电力行业现场运维人员对Netty的复杂抽象相对陌生出问题不好排查。用原生ServerSocket/Socket加一个简单的线程模型稳定性反而更可控。整体架构可以划分为三层各干各的通信接入层负责TCP连接管理、报文解码、链路握手、超时心跳。最简单的做法是一个连接一个读线程 一个全局发送线程池连接断开时由独立的Reconnect线程负责重连。业务解析层负责APCI的计数控制、ASDU解析、上行数据的类型分发遥信、遥测、SOE、时钟同步响应、命令确认下行命令的封装遥控/遥调选择、执行、撤销、总召唤、时钟同步。数据持久层使用阻塞队列作为缓冲消费线程定时批量写入数据库保证高并发下数据库的连接数不会被打满。这里先用一个表把协议栈里最核心的东西列出来后面详细展开功能模块对应IEC 104机制工程实现关键点链路启动U帧 STARTDT act/con必须等STARTDT con后再发总召唤总召唤C_IC_NA_1 (100)定期召唤全量数据用于对点/刷新时钟同步C_CS_NA_1 (103)子站时间不准SOE时间戳全是错的遥信上报M_SP_NA_1 (1)、M_DP_NA_1 (3)变位主动上送主站要记录SOE时标遥测上报M_ME_NC_1 (13) M_ME_NB_1 (11) M_ME_NA_1 (9)短浮点13最常见注意大小端遥控命令C_SC_NA_1 (45)、C_DC_NA_1 (46)选择-执行机制控制方向需带S/E标志遥调命令C_SE_NC_1 (50)、C_SE_NB_1 (49)设点命令同样有选择-执行流程2. IEC 104协议核心细节解析与实现2.1 报文结构APCI与ASDU怎么理解很多新手看到IEC 104报文就头疼满眼都是十六进制。其实就是个套娃结构。每一帧由APCI应用协议控制信息 ASDU应用服务数据单元组成。APCI固定6个字节启动字符0x68 长度 控制域4字节ASDU是可变长度的应用数据。以一条常见的单点遥信M_SP_NA_1为例报文长这样68 0A 0E 16 00 00 01 02 03 00 01 00 00 01 01 01拆解一下68启动字符固定值。0AAPDU长度表示后面还有10个字节APCI控制域4字节 ASDU 6字节。0E 16 00 00控制域这里是I帧发送序号等于0x0000160E数值无所谓关键看I格式标志最低位为0。01ASDU类型标识M_SP_NA_1即单点遥信。02可变结构限定词VSQ低7位表示信息对象个数这里2表示这条报文里带2个遥信点。03传送原因COT这里有两位低6位表示原因0x03表示突发最高位P/N0表示肯定确认。00公共地址低字节01公共地址高字节如果公共地址长度是2这里就是01 00各厂家的配置不一样必须看子站的装置参数。后面就是信息对象信息体地址3字节 遥信值1字节 品质描述1字节。一个工程上常用的判断技巧拿到一条报文先看0x68后面的长度字节再算一下ASDU长度是否吻合不吻合直接丢弃。有问题的报文很多尤其在多子站接入、链路刚启动的阶段各种非标厂家设备会给你一些惊喜。2.2 遥信遥测解析的关键点品质描述与变位上送遥信M_SP_NA_1和遥测M_ME_NC_1解析本身不复杂难在两点品质描述Quality和信息体地址映射。品质描述字节QDS只有1个字节但它的每一位都有具体含义。bit0是IV是否有效bit1是NT是否刷新bit2是SB是否取代bit3是BL是否闭锁bit4-7是溢出标志等。我在解析时强制要求IV位为1的数据不能直接入库要打上无效标记否则历史曲线里会出现跳变的坏数据。这在光伏等波动性强的数据上尤为常见——有时候逆变器通信卡顿上送的数据就是无效的如果不处理后面做数据分析的人会拿着这些坏数据骂娘。再一个是变位上送。IEC 104子站的默认行为是遥信变位立即主动上送传送原因COT3突发、11当地/远方操作同时带SOE时标通常用的类型是M_SP_TB_1类型号30。主站需要把时标解析出来并与报文到达时间做偏差计算。我在实际测试中发现某些厂家的规约转换器时标解析出来是有偏差的可能与实际时间差了几分钟甚至几小时——排查之后发现是子站装置没有做时钟同步或者同步周期太长。所以主站程序里我加了一个定时任务每隔一定周期下发一次时钟同步命令C_CS_NA_1把主站的标准时间广播给子站同时记录各子站的时钟偏差便于定位问题。2.3 遥控遥调选择-执行机制必须做对命令下发是整套程序里对安全要求最高的模块。IEC 104的遥控流程是一个标准的两次握手下发选择命令S/E标志位1等待子站返回选择确认确认无误后再下发执行命令S/E标志位0等待执行确认。下面是单点遥控C_SC_NA_1的报文示例选择命令控制方向68 0A 00 00 00 00 2D 01 06 00 01 00 00 00 01 81 002DC_SC_NA_1遥信单点命令01VSQ一个信息对象06传送原因6激活 Activation00 01公共地址00 00 01信息体地址具体点号由工程点表决定01S/E1表示选择Select81是带品质描述的遥控字节最高位表示合/分这里合低字节是S/E标志和命令状态00是保留字节。执行命令只需要把81改成01S/E0传送原因改成06即可。工程上最容易犯的错误是遥控选择成功后没有等子站返回选择确认就把执行命令发出去了或者把选择帧的长度、信息体地址算错了。这样轻则被子站丢弃重则在变电站/并网柜上造成误操作风险。我的做法是在代码里加一个命令状态机每个命令对象都有IDLE - SELECT_SENT - SELECT_CONFIRMED - EXECUTE_SENT - EXECUTE_CONFIRMED 这几个状态任何一步超时或报文不匹配就终止流程并产生告警记录。遥调设点命令本质上和遥控一样只是信息对象里携带了一个设定值短浮点或标度化值。常见的是C_SE_NC_1短浮点设点用于给PCS下发有功功率/无功功率目标值。这个值在报文里是按照IEEE 754浮点数存储的注意大小端和字节序——我在项目里就踩过一次PCS功率目标值下发后直接变成了几百兆瓦吓得当场切了手动后来发现是浮点字节序解析反了。2.4 链路关键参数和定时器配置IEC 104对通信过程的稳定性有一整套定时器规定分别是t0连接建立超时、t1发送/确认超时、t2无数据报文时发送S帧的确认超时、t3链路测试帧发送周期、以及K和W窗口参数。每个连接都要单独维护这些参数。参数默认值作用我们项目实际配置t010sTCP连接建立超时15st115s等待对方确认响应15st210s收到数据后最长等待时间发S帧确认10st320s链路空闲时发送TESTFR维持心跳30s现场要求放宽K12发送方最大未确认I帧数12W8接收方最大未确认I帧数8这些参数必须可以在配置文件里调整因为不同子站厂家对参数的支持程度千差万别。有的子站t3设20s会频繁断链因为它的链路检测周期比较长主站持续发测试帧它反而认为异常所以最后我们把这些参数做成可配置项每个连接独立维护一套。3. 多线程Socket通信与线程模型3.1 选型BIO还是NIO这项目我最终选了BIO 多线程理由前面说过一半。再补充一个更实际的原因IEC 104的子站数量不会特别多一般几十个连接顶天了。每个连接起一个读线程资源开销完全扛得住。而且BIO的代码逻辑简单直白一个线程阻塞读收到报文就丢给处理队列出问题好排查。如果用NIO的Selector模型虽然能支撑上万连接但代码复杂度成倍上升多路复用的事件处理、半包粘包处理、状态维护任何一个细节考虑不到都会造成隐性Bug。3.2 线程模型设计我设计的线程模型如下每连接一个读线程负责循环调用Socket.getInputStream().read()读入APDU然后按照IEC 104的帧格式解析。读取的时候要处理粘包和半包问题我的做法是自定义一个ByteBuffer累积缓冲区每次读到数据先判断长度是否足够不足则等待下一次读取。全局发送线程池所有需要发送的报文总召唤、遥控命令、时钟同步、S帧确认都通过一个ExecutorService发送避免多线程同时写同一个Socket造成报文交叉错乱。每个连接一个独立的发送队列发送线程从队列取报文加锁写socket。业务处理线程池解析出来的ASDU数据包不直接入库先丢进一个有界阻塞队列比如ArrayBlockingQueue由一个独立的消费者线程池处理数据映射、告警判断、数据库写入。这样即使数据库出现短暂阻塞也不会影响通信层读线程的稳定性。连接监控线程定时扫描所有连接的活跃状态发现超时无数据的连接就发送TESTFR测试帧连续几次无响应则强制断开由重连线程负责重连。这里有一个非常容易被忽略的坑Socket的读写超时时间必须设置而且要小于t1和t3。如果不设置读线程会一直阻塞在一个死掉的连接上连接断开事件无法及时感知。TCP本身虽然有KeepAlive但默认探测周期太长不适用于这种要求秒级断链检测的场景。3.3 链路管理与断线重连机制断线重连是现场运维的重灾区。实际项目中子站装置重启、网络交换机重启、光纤松动、PLC死机都会导致TCP连接断开。主站程序必须做到连接断开后自动重连并且重连成功之后自动重新启动链路、重新总召唤一次保证数据完整。重连策略不能太激进否则会出现连接风暴——子站还没来得及完成初始化和装置自检主站就在疯狂重连双方都起不来。我用的策略是首次断开后延迟5秒重连重连失败后延迟翻倍但最大不超过60秒连续重连成功一次后延迟重置为5秒。重连成功后程序自动执行一次完整的链路握手流程TCP connect - 发送STARTDT act - 等待STARTDT con - 发送总召唤 - 发送时钟同步。整个流程有超时控制任何一个环节失败都会重新断开并进入重连周期。4. 高并发数据库操作的实现4.1 数据写入特点与瓶颈分析IEC 104主站客户端最容易被低估的就是数据入库压力。以一个中等规模的微电网为例假设接入10个子站每个子站有500个遥测点、300个遥信点按2秒一个周期上报实际上很多子站是变位实时上送稳态周期扫描一天产生的数据量就是800点 × 10子站 × 86400秒/2秒 ≈ 3.5亿条。这个数量级如果每条都实时insert任何数据库都扛不住。所以说高并发数据库操作的第一课不是怎么写SQL而是怎么减少SQL。基本思路是批量入库 队列削峰 定时落盘。4.2 阻塞队列 批量写入我在程序里用了一个LinkedBlockingQueue作为数据缓冲队列。通信层解析出数据后封装成DataPoint对象放入队列数据库写线程从队列里批量取出比如每次取500条或攒够1秒的数据然后执行批量insert。批量insert在MySQL里用单条SQL多VALUES的方式或者在JDBC层面使用addBatch()executeBatch()。实测下来使用JDBC Batch插入500条数据比逐条插入快20倍以上数据库连接占用也从每秒几十次降到每秒1-2次。一个写线程可能不够可以根据队列积压情况动态调整线程数。但注意写线程数不是越多越好磁盘IO和数据库锁才是瓶颈。我一般控制写线程数在3-5个每个线程负责不同的表分区或者按测点哈希分片避免多个线程同时竞争同一张表的行锁。4.3 连接池配置与SQL优化连接池用的是HikariCP这个连接池性能好、稳定性高Spring Boot默认集成。关键的配置参数spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000针对IEC 104场景我专门调整了maximum-pool-size默认10不够用。因为有批量写线程、历史查询线程、业务查询线程同时都要拿连接连接太少会导致线程等待进而引起队列积压最后缓存数据堆积造成OOM。另外SQL层面有一件事必须做对测点表、历史数据表按时间分区。微电网的数据都是时序数据查询基本都带时间范围。MySQL按天/周分区的效果很显著插数据和查询都走分区裁剪不会越查越慢。4.4 冷热数据分离与归档策略历史数据不能无限堆积。我们项目里的策略是实时库保留最近3个月的数据用于实时监控和短期分析每月月底把3个月前的数据归档到历史库或者直接导出为文件存冷存储。归档任务使用一个定时线程在凌晨低峰期执行避免影响白天数据写入。同时要注意数据库表设计时主键不要用自增ID推荐使用子站编码信息体地址时间戳组合的唯一键。这样做有几个好处数据天然有序、可以走覆盖索引、批量插入时冲突检测也方便。我之前用自增ID结果有一次程序重复解析上报了一批数据主键冲突搞出一堆异常日志后来改成业务唯一键INSERT ... ON DUPLICATE KEY UPDATE干净利落。5. 核心代码实现与关键细节5.1 链路握手与消息发送链路启动和TCP连接建立是程序生命周期中最关键的一步。核心代码逻辑如下public class Iec104Connection implements Runnable { private Socket socket; private OutputStream out; private InputStream in; private volatile boolean running true; public void connect() throws IOException { socket new Socket(); socket.connect(new InetSocketAddress(host, port), t0 * 1000); socket.setSoTimeout(t1 * 1000); socket.setKeepAlive(true); out socket.getOutputStream(); in socket.getInputStream(); // 发送STARTDT act sendStartdtAct(); // 等待STARTDT con waitStartdtCon(); // 启动后发送总召唤 sendGeneralInterrogation(); } private void sendStartdtAct() throws IOException { byte[] startdtAct new byte[]{ (byte) 0x68, 0x04, 0x07, 0x00, 0x00, 0x00 }; out.write(startdtAct); out.flush(); } }这里有几个细节需要特别注意0x68 0x04是U帧的固定头部后面四个字节是控制域。STARTDT act的控制域是0x07 0x00 0x00 0x00STARTDT con是0x0B 0x00 0x00 0x00STOPDT是0x13开头TESTFR是0x43开头。U帧格式里控制域的bit0为1bit21表示STARTDTbit41表示TESTFR。发送的时候不要搞混。如果子站不支持STARTDT握手有些不规范的子站直接跳过这个流程程序里要做兼容发送STARTDT act后等待一段时间如果收到子站主动上送的I帧数据也不强制报错而是继续处理。5.2 报文的读取与粘包处理网络通信最核心的问题就是粘包和半包。TCP是流式协议没有消息边界所以必须自己根据IEC 104的帧结构来切分。private void readLoop() { // 累积缓冲区 ByteArrayOutputStream buffer new ByteArrayOutputStream(); byte[] temp new byte[2048]; int len; try { while (running (len in.read(temp)) ! -1) { buffer.write(temp, 0, len); byte[] data buffer.toByteArray(); int processed processBuffer(data); // 移除已处理的前半部分保留剩余未处理的字节 byte[] remaining Arrays.copyOfRange(data, processed, data.length); buffer.reset(); buffer.write(remaining); } } catch (IOException e) { // 连接异常触发重连 } } private int processBuffer(byte[] data) { if (data.length 6) { return 0; // 连APCI头都不完整继续等待 } int length data[1] 0xFF; // APDU长度 APCI 4字节 ASDU长度 if (data.length length 2) { return 0; // 半包继续等 } // 取出一个完整帧 byte[] frame Arrays.copyOfRange(data, 0, length 2); handleFrame(frame); return length 2; }注意IEC 104的APDU长度字段是从控制域第一个字节开始算的所以一个APDU的总字节数是length 2启动字符和长度字节本身不算在内。这个细节做长度校验的时候要非常小心算错一位就会造成整条链路死锁。5.3 遥控命令状态机实现遥控部分我用一个简单的状态机来管理。每次用户发起遥控先创建一个CommandTask对象丢给命令发送队列。public class CommandTask { private final int commandId; private final int infoAddr; private final boolean isClose; // true合, false分 private CommandState state CommandState.IDLE; public enum CommandState { IDLE, SELECT_SENT, SELECT_CONFIRMED, EXECUTE_SENT, EXECUTE_CONFIRMED, FAILED, SUCCESS } }当收到子站返回的选择确认报文时程序根据信息体地址找到对应的CommandTask把状态从SELECT_SENT推送到SELECT_CONFIRMED然后自动发送执行命令。如果超时比如超过10秒还没收到选择确认直接标记为FAILED并报遥控超时告警。这个状态机的价值在于它让整个遥控流程可追踪、可回放、可告警。只要有告警记录事后排查问题就有线索。比如现场值班人员说我点了合闸没反应你翻一下告警记录立刻能看出是选择命令没发出去还是子站没回应还是执行确认丢了。5.4 数据库批量写入示例批量写库的代码逻辑不复杂但有个坑必须说JDBC的rewriteBatchedStatements参数一定要设为true。如果不设置MySQL的JDBC驱动会把executeBatch()拆成逐条执行性能提升直接归零。// 连接URL中加上 rewriteBatchedStatementstrue String url jdbc:mysql://localhost:3306/microgrid?useSSLfalserewriteBatchedStatementstrueserverTimezoneAsia/Shanghai; public void batchInsert(ListDataPoint points) { if (points.isEmpty()) return; String sql INSERT INTO tb_measure_point ( station_id, info_addr, data_type, value, quality, collect_time ) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE value VALUES(value), quality VALUES(quality); try (Connection conn dataSource.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { for (DataPoint p : points) { ps.setString(1, p.getStationId()); ps.setInt(2, p.getInfoAddr()); ps.setInt(3, p.getDataType()); ps.setDouble(4, p.getValue()); ps.setByte(5, p.getQuality()); ps.setTimestamp(6, p.getCollectTime()); ps.addBatch(); } ps.executeBatch(); } catch (SQLException e) { log.error(批量写入失败数据条数: {}, points.size(), e); } }注意这里的ON DUPLICATE KEY UPDATE对于同一时刻重复上报的数据比如异常重传会直接覆盖而不是插入第二条。这个设计在应对乱序上报时非常有用。6. 常见问题与排查技巧实录6.1 链路连不上先看TCP再看握手最常遇到的问题就是TCP能通但程序一直发STARTDT act收不到con或者收到了con但子站不上报数据。排查顺序是先telnet ip 2404测试端口通不通。用抓包工具Wireshark IEC 104解析插件抓包看TCP握手和APDU交互过程。重点确认子站的公共地址common address是否与主站配置一致不一致的话所有报文都会被丢弃。确认子站是否启用了IEC 104服务端功能有些规约转换器默认只开101串口104端口没启用。如果TCP连上但没有任何数据大概率是STARTDT没握手成功或者子站等待总召唤。6.2 报文对不上注意大小端和地址长度IEC 104在具体实现中有一个最坑的地方不同设备商对字节序和信息体地址长度的约定不一致。有的子站用低字节在前有的用高字节在前有的公共地址是1字节有的是2字节还需要根据实际装置参数做配置。我的做法是所有涉及地址和长度的字段都做成可配置的并且解析时打印完整的报文hex日志这样即使出了错也能快速比对。生产环境一定不要关掉报文日志只要有这个日志90%的通信问题都能定位。6.3 程序运行一段时间后OOM这项目跑着跑着出现过一次OutOfMemoryError。排查后发现是数据缓冲队列无限增长导致的数据库暂时不可用批量写线程阻塞但通信层还在不停解析报文放入队列队列无界最终内存耗尽。解决方案是双层保险把无界队列换成ArrayBlockingQueue并设置队列最大容量比如5万条。当队列满时直接丢弃数据并记录数据溢出告警而不是阻塞读线程。另外把JVM堆从默认的物理内存1/4调整为4GB显式设置-Xms4g -Xmx4g并加-XX:HeapDumpOnOutOfMemoryError方便下次出问题直接分析堆转储文件。6.4 数据库写入慢导致队列积压数据库批量写入慢先看是不是数据库的连接池参数没调好再看是不是索引太多导致插入慢。我在实际项目里发现数据表上的索引不是越多越好每增加一个索引insert性能就下降一截。如果数据表有5个以上索引插入性能会明显恶化。解决方案是历史数据表只保留最必要的一两个索引如(station_id, collect_time)联合索引其他的索引建在归档表上实时写入表尽量精简。6.5 故障速查表现象可能原因处理办法TCP连接失败子站IP端口不通、防火墙拦截telnet测试检查网络和安全策略连接成功但收不到数据STARTDT未握手、公共地址不匹配、未发总召唤抓包核对握手流程检查公共地址数字乱跳/负数很大字节序解析错误、浮点位序不对打印hex日志对比协议规范调整解析遥控无响应S/E标志错误、信息体地址不对、子站未返校查看命令状态机日志手动测试单个命令数据库连接池满连接泄漏、大批量查询未释放打开连接池监控排查慢SQL和未关闭连接队列积压/OOM数据库阻塞、队列无界、堆太小换有界队列批量写优化调大堆内存链路频繁断开重连t3/t1参数不匹配、网络抖动调整定时器参数开启TCP keepAlive检查交换机端口尾声做IEC 104主站这个项目给我最大的体会就是协议本身并不复杂复杂的是现场环境和各种厂家设备的个性。同一个协议不同子站实现得千差万别有的严格按标准有的打着标准旗号各种自由发挥。所以这套程序在设计上我始终遵循一个原则健壮性优先宁可多打印一条日志也不要让系统因为未知情况直接崩溃。最后再分享一个小技巧调试IEC 104的时候建议准备一个模拟子站比如用开源IEC 104模拟器用来做协议自测。有了模拟子站很多需要反复测试的流程重连、遥控确认、时钟同步、链路异常都可以在实验室里跑熟再上现场就会从容很多。今天把这些细节和踩过的坑整理出来希望能给打算做电力规约接入的朋友省一些时间。本文还有配套的精品资源点击获取
返回列表