运维群那天下午有点闹。电站运维专责连着发了三条消息,说某光伏电站的发电量报表导出一直转圈,等了五六分钟还没反应。一开始我以为是他们内网带宽问题,让他换个浏览器再试一次。结果半小时后其他几个电站也陆陆续续反馈同样的情况——凡是按这个电站选三个月以上时间范围导出,必定卡死。我登录后台看了一眼,接口日志里那条查询 SQL 的执行时间已经飙到了 280 多秒,整个应用的内存曲线也明显异常。
这类“某个电站导出慢”的问题,在电站监控平台、物联网数据平台里其实非常典型。它不是普通的查询性能问题,而是数据量、索引设计、SQL 执行计划、导出链路设计等多个因素叠加之后暴露出来的综合故障。这篇文章把我们这次从现象、排查、根因到修复的完整过程记录下来,包括每一步为什么这样做、踩了哪些容易忽略的坑,希望能给做电站监控系统、数据平台或者类似报表导出功能的朋友一些参考。
1. 故障现场:一个电站的导出请求卡成了“黑洞”
1.1 三个典型症状,指向同一个方向
导出的问题往往不是“突然不能用”,而是“有一个点特别慢,其他点看起来还能用”。那天我们遇到的故障有三个典型症状,任何一个单独出现都可能被当成偶发问题,但三个同时出现,基本就把排查方向圈定了。
第一个症状,Web 端导出任务长时间无响应。正常状态下,选择一个电站、三个月时间范围、导出运行数据 CSV,后端接口 2 到 3 秒就能返回下载链接。出问题的时候,前端页面一直显示“生成中”,超过 30 秒之后浏览器请求直接超时,用户换浏览器、换网络、清缓存都不管用,说明问题大概率不在前端。
第二个症状,后端日志显示该电站的查询 SQL 耗时异常。我们的监控平台在 ORM 层做了慢 SQL 日志拦截,凡是执行超过 2 秒的 SQL 都会记录到独立的日志文件。那天从日志里翻出来的 SQL,单单查询阶段就跑了 286 秒,而且这条 SQL 的入参里 station_id 稳定指向同一个电站。
第三个症状,导出期间应用服务器频繁 Full GC。导出不是瞬时动作,几百秒的查询意味着大量结果集堆积在内存里,JVM 老年代持续上涨,垃圾回收线程一直在做无用功,最终导致同服务上的其他接口也出现明显的响应延迟。这个症状很容易被忽略,但它其实是“导出的数据量已经超出预期”的直接信号。
1.2 为什么单独这个电站成了“异常电站”
我们平台接入了几百座电站,有大有小。这个出问题的电站,刚开始并没有被特别关注,直到导出慢的反馈集中爆发,我们才去翻了它的元数据:接入的逆变器、汇流箱、气象站等设备数量接近 3200 台,是同体量其他电站的三倍以上;而且它的数据采集频率从标准的 5 分钟一次调整到了 1 分钟一次,等于单位时间内的数据量又翻了五倍。两件事一叠加,这个电站单月产生的历史数据量就能达到其他电站一整年的量级。
这里想说明一个概念上的问题。“异常电站”不一定是设备故障,更多时候是数据分布上的极端个体。我们平时做性能测试,通常会按“平均水位”来设计——取几十个电站的数据量平均值,推导出查询耗时、内存占用的合理范围。但这个电站直接是“极端水位”,它的数据量远超平均值,之前没有专门针对这种规模做过导出场景的压测,所以问题只在它身上暴露出来,其他电站一切正常。
1.3 影响面评估:先止血还是先深挖
评估影响面的时候,我们分了两条线。一条是“故障边界”,确认它只影响导出报表,不影响实时采集、阈值告警、设备控制这些核心链路,也就是说电站本身的安全生产没有受到威胁,可以按常规故障流程处理。另一条线是“蔓延风险”,排查是否还有其他电站的数据量正处于快速膨胀阶段,如果存在同样的趋势而不干预,未来几个月会陆续暴雷。这条线直接决定了我们不能只做一次性修复,必须沉淀出可复用的优化手段和监控指标。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 导出链路拆解:在动手排查前先画清楚数据走向
2.1 导出的整体技术架构
这个平台的导出功能,走的是一条非常典型的 Web 报表链路:前端基于 Vue,用户选择电站、数据类型、时间范围后,向后端发起导出请求;后端是 Spring Boot 服务,提供 /api/export/stationData 接口;数据访问层用的 MyBatis-Plus,SQL 写在 XML 文件里;存储是 MySQL 8.0 InnoDB 引擎,历史采集数据按月分表,表名类似 device_data_202403;文件生成用的 EasyExcel,按流式方式写 Excel 或 CSV。
链路本身不复杂,但有一个关键点:它是一个同步导出接口。也就是说,用户发起请求后,HTTP 连接一直挂着,后端线程要等到 SQL 全部查完、结果集全部写入文件、文件上传到临时存储之后,才能把下载地址返回给前端。任何一个环节耗时过长,都会表现为“页面一直转圈”。这个设
