1. 项目概述与核心需求
最近在风电行业做了个挺有意思的物联网监控系统,用SpringBoot搭建的风电场集中管理平台。这个系统的核心目标是把分散在几十平方公里范围内的风机运行状态实时采集上来,让运维人员在一个平台上就能掌握所有设备的健康状况。
系统主要解决三个关键问题:
- 实时数据采集与可视化:需要处理每秒上千条传感器数据,包括风速、转速、功率等20多项参数
- 故障预警与处理:当叶片结冰、齿轮箱过热等异常发生时,要立即通知相关人员
- 历史数据分析:统计发电效率、设备损耗等指标,为运维决策提供依据
技术栈选型上,后端用SpringBoot 2.7 + Netty + MyBatis,前端Vue3 + ECharts,数据库MySQL + Redis时序数据库。特别说明下为什么选Netty而不是WebSocket原生实现——在实测中,Netty处理二进制协议的性能比传统WebSocket高3倍以上,这对于要同时处理200+台风机的场景至关重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 整体架构分层
系统采用经典的四层架构:
code复制[设备层] <-TCP-> [接入层] <-HTTP-> [业务层] <-DB-> [数据层]
设备层:各风机内置的PLC控制器,通过4G模块上报数据
接入层:Netty服务集群,负责协议解析和连接管理
业务层:SpringBoot微服务,处理业务逻辑
数据层:MySQL存业务数据,RedisTS存时序数据,MinIO存故障图片
2.2 通信协议设计
与风机通信采用行业标准的Modbus TCP变种协议,数据帧格式如下:
| 偏移量 | 长度 | 说明 |
|---|---|---|
| 0 | 2 | 帧头 0x55AA |
| 2 | 1 | 风机ID |
| 3 | 1 | 数据类型 |
| 4 | 2 | 数据长度 |
| 6 | N | 数据体 |
| 6+N | 2 | CRC校验 |
在代码中我们用了ByteBuf做高效解析:
java复制public WindTurbineData parse(ByteBuf buf) {
if (buf.readShort() != 0x55AA) {
throw new IllegalProtocolException("Invalid frame header");
}
byte turbineId = buf.readByte();
byte dataType = buf.readByte();
int length = buf.readUnsignedShort();
byte[] data = new byte[length];
buf.readBytes(data);
// 后续根据dataType调用不同解析方法
return switch(dataType) {
case 0x01 -> parseStatusData(turbineId, data);
case 0x02 -> parseFaultData(turbineId, data);
default -> throw new IllegalProtocolException("Unknown data type");
};
}
2.3 数据存储设计
针对不同的数据类型采用不同的存储策略:
- 实时状态数据:Redis时序数据库,按风机ID分片,保留最近7天数据
- 故障记录:MySQL集群,建立时间+设备ID联合索引
- 统计报表:每天凌晨跑Spark任务生成聚合结果存入MySQL
这里有个优化点:最初我们把所有数据都存MySQL,结果一周就爆表。后来改用RedisTS存原始数据,查询性能提升了20倍。
3. 核心功能实现
3.1 实时数据采集
数据采集服务要解决三个关键问题:
- 断线重连:内置心跳机制,30秒无数据自动重连
- 数据补传:设备端会缓存断网期间的数据
- 流量控制:采用令牌桶算法限制最大QPS
核心采集逻辑如下:
java复制@ChannelHandler.Sharable
public class TurbineHandler extends ChannelInboundHandlerAdapter {
private final TokenBucket tokenBucket = new TokenBucket(1000); // 1000条/秒
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (!tokenBucket.tryAcquire()) {
ctx.writeAndFlush(new BusyCommand());
return;
}
ByteBuf buf = (ByteBuf) msg;
try {
WindTurbineData data = protocolParser.parse(buf);
dataQueue.publish(data); // 写入Kafka
updateDashboard(data); // 更新实时看板
} finally {
buf.release();
}
}
}
3.2 故障处理机制
我们定义了四级故障等级:
| 等级 | 响应时间 | 通知方式 |
|---|---|---|
| 紧急 | 5分钟 | 短信+电话 |
| 重要 | 30分钟 | 企业微信 |
| 一般 | 4小时 | 邮件通知 |
| 提示 | 24小时 | 站内消息 |
故障处理流程的状态机实现:
java复制public interface FaultState {
void handle(FaultContext context);
}
public class NewState implements FaultState {
@Override
public void handle(FaultContext context) {
FaultRecord record = context.getRecord();
if (record.getLevel() >= FaultLevel.URGENT) {
smsService.sendAlert(record);
}
context.changeState(new ProcessingState());
}
}
3.3 可视化大屏
前端采用ECharts实现的关键图表:
- 风玫瑰图:展示风向分布
javascript复制function initWindRose() {
chart.setOption({
angleAxis: { type: 'category', data: ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'] },
radiusAxis: { min: 0 },
series: [{
type: 'bar',
data: windData,
coordinateSystem: 'polar'
}]
});
}
- 功率曲线:实时显示发电量变化
- 设备健康度热力图:用颜色标识各部件状态
4. 性能优化实践
4.1 数据库优化
针对时序数据的高频写入特点,我们做了这些优化:
- 批量插入:使用MyBatis的批量模式,每次插入100条
xml复制<insert id="batchInsert" parameterType="list">
INSERT INTO turbine_data VALUES
<foreach collection="list" item="item" separator=",">
(#{item.turbineId}, #{item.timestamp}, #{item.value})
</foreach>
</insert>
- 冷热分离:3个月前的数据自动归档到对象存储
- 读写分离:用ShardingSphere实现分库分表
4.2 缓存策略
采用多级缓存架构:
- 本地缓存:Caffeine缓存常用配置信息,TTL 5分钟
- 分布式缓存:Redis集群缓存实时数据
- 浏览器缓存:ETag协商缓存静态资源
4.3 前端优化
- 虚拟滚动:只渲染可视区域内的数据点
- WebWorker:将数据处理移出主线程
- 增量更新:WebSocket只推送变化的数据字段
5. 典型问题排查
5.1 数据抖动问题
现象:功率曲线出现频繁的尖峰
排查过程:
- 检查设备信号强度(正常)
- 查看原始数据报文(发现异常值)
- 联系设备厂商确认协议细节
最终发现是PLC的ADC采样电路受温度影响,通过以下措施解决:
- 增加软件滤波算法
- 在设备端配置温度补偿
- 对异常值进行平滑处理
5.2 内存泄漏问题
现象:服务运行几天后OOM
排查工具:
- jmap生成堆转储文件
- MAT分析内存占用
发现是Netty的ByteBuf没有正确释放,修复方案:
java复制@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
// 业务处理
} finally {
ReferenceCountUtil.release(msg); // 确保释放
}
}
5.3 分布式事务问题
跨系统数据同步时出现不一致,最终采用本地消息表方案:
- 业务操作和消息写入在同一个事务
- 定时任务扫描未发送的消息
- 消费端实现幂等处理
6. 部署与运维
6.1 容器化部署
使用Docker Compose编排服务:
yaml复制services:
collector:
image: wind-collector:1.2
ports: ["9000:9000"]
deploy:
resources:
limits:
cpus: '2'
memory: 2G
6.2 监控方案
- Prometheus采集JVM指标
- Grafana展示监控看板
- ELK收集业务日志
关键监控指标:
- 采集延迟
- 消息积压量
- 故障处理时效
6.3 灾备方案
- 双活数据中心部署
- 实时数据同步延迟<1s
- 定期演练故障切换
7. 项目总结
这个项目给我最大的启示是:物联网系统要特别关注"端-边-云"协同。我们在二期做了这些改进:
- 边缘计算:在风机端部署轻量级AI模型,提前过滤异常数据
- 预测性维护:基于历史数据训练设备寿命预测模型
- 数字孪生:构建3D可视化风机模型
有个特别实用的经验:所有设备通信指令都要留审计日志。有次客户投诉说系统误发停机命令,我们通过查询日志发现是他们的维护人员手动操作的,避免了责任纠纷。
