去年 7 月,我们接手了一个苏南地区的分布式代运维项目,涉及到 400 多个工商业屋顶电站,总装机容量接近 600MW。当时甲方自研的平台跑了不到一周,后端 InfluxDB 就开始频繁报 503 Service Unavailable。查了日志发现,不仅是高并发写入的问题,更多是因为每家逆变器厂商的 API 返回格式、字段精度、甚至时间戳时区都不一样,导致入库逻辑乱成了一锅粥。
很多做能源数字化的团队,第一反应是把数据接进来、存起来。但光伏电站的数据有其特殊性:它不是简单的 CRUD,而是典型的高频时序数据。一个 50MW 的站,如果按 5 分钟间隔拉取,看似压力不大;但如果要支撑调频、调峰或者做更精细的功率预测,采集频率通常会拉到 3 秒到 10 秒。这时候,如果你的架构还停留在「拉一个 API 存一条记录」的原始阶段,翻车是早晚的事。
我们今天不聊那些高大上的 PPT 架构,就实打实地拆解一下,从边缘侧的厂商 API 到云端 InfluxDB,这条链路上的坑到底是怎么填平的。
第一关:API 采集层的「流量地狱」与字段归一
大多数人对接华为、阳光、古瑞瓦特这些厂商云 API 时,最容易撞上的就是限流(Rate Limiting)。比如某头部厂商的 API,默认只允许每分钟 10 次调用。如果你有 500 个电站,每个电站单独去轮询,瞬间就会被封 IP。
我们在处理这个项目时,放弃了「电站级轮询」,改成了「组织级/账号级批拉」。通过一个 Token 批量拉取下属所有电站的实时列表。这里有个细节:不同厂商的 API 返回值里,电量的单位可能是 kWh,也可能是 MWh,功率可能是 W 也可能是 kW。甚至有的厂商在凌晨 0 点到 4 点会停止数据更新,返回空值或最后一次历史值。
为了解决存储前的混乱,我们必须建立一层「归一化映射表」。以下是我们内部常用的一套归一化字段参考:
| 标准字段名 | 业务含义 | 推荐数据类型 | 备注 |
|---|---|---|---|
active_power |
有功功率 | Float (kW) | 强制统一为 kW,保留 3 位小数 |
daily_yield |
当日发电量 | Float (kWh) | 需处理部分厂商累积电量清零逻辑 |
v_pv1 |
PV1 路电压 | Float (V) | 多路 MPPT 需拆分存储 |
status |
运行状态 | Integer | 归一化为:0-待机, 1-运行, 2-故障 |
第二关:大数据网关的缓冲逻辑------不要让数据库直面洪水
在数据进入 InfluxDB 之前,必须有一个「中间层」来做缓冲和削峰填谷。我们当时用了 Redis 作为一级缓存,配合一个基于 Go 写的消费端。为什么要这么做?
- 补传机制(Backfilling) :光伏电站的通信链路极不稳定,4G 信号断了是常态。厂商 API 经常会补传前两个小时的数据。如果你直接往时序数据库写,InfluxDB 的 TSM 引擎在处理「过去时间戳」的写入时,IO 压力比「当前时间」大得多。我们需要在消费端识别这些历史数据,进行批量的
Upsert操作。 - 数据降采样(Downsampling):对于运维监控,3 秒一次的数据太密了,看板根本不需要这么高的频率。我们在网关层做了一个简单的滑动平均过滤,把 3 秒的高频数据聚合为 1 分钟的基准点存入生产库,而原始高频数据则存入低频访问的冷存储。
sql
-- 典型的 InfluxDB 写入行协议格式示例
-- measurement,tags fields timestamp
device_telemetry,inverter_sn=SN123456,station_id=ST_001 active_power=45.2,daily_yield=120.5,temp=42.3 1689235200000000000
第三关:InfluxDB 的架构设计------拒绝「基数爆炸」
这是很多工程师最容易栽跟头的地方。InfluxDB 的查询性能取决于 Series Cardinality(序列基数)。如果你把逆变器的序列号(SN)、型号、甚至每天生成的告警 ID 都作为 Tag,基数会迅速膨胀到几百万,最后导致内存溢出。
我们的方案是:
- Tags 只放索引 :只放
station_id(电站 ID)和device_id(设备 ID)。 - Fields 放数值:功率、电压、电流、温度。这些不建立索引,查询时通过 Tag 过滤后进行 Scan。
- Retention Policy (RP) :我们设置了两个 RP。实时库保留 30 天数据,采用高性能 SSD;历史库保留 5 年数据,存放在容量大的机械硬盘阵列上,并定期触发
Continuous Queries (CQ)进行数据下采样。
在那个 600MW 的项目中,我们通过这套架构,将原本每秒 8000 次的随机写入优化成了每 5 秒一次的批量写入,数据库 CPU 占用率从 85% 降到了 12% 左右。
我们的思考与取舍
做光伏数据采集,千万不要迷信「通常实时」。在公有云 API 的限制下,所谓的实时其实都是「伪实时」。真正的挑战在于如何处理那 30+ 厂商千奇百怪的错误码,以及如何在 API 变更时不需要重构你的数据库表结构。
我们后来把这套针对多厂商 API 对接、字段归一、以及高并发写入的逻辑,封装成了一个专门的中间件,也就是我们内部一直在迭代的 ZenovaConnect。它的核心价值就是把这些脏活累活干了:不管是华为的北向接口,还是阳光云的 API,接进来之后,推给你的都是统一格式的 JSON 或时序数据包。这样你上层的 EMS 或分布式监控平台,只需要关注业务逻辑,不用再跟那些写得像天书一样的 API 文档死磕。
如果你现在也面临多品牌逆变器接入、数据存不进或者查不出的窘境,建议先回过头看看你的 Tag 设计是否合理。毕竟在能源数字化这条路上,数据接进来只是第一步,能存住、能算快,才是硬本事。
你目前在用的时序数据库是哪一家?在处理多厂商数据归一时,最让你头疼的字段是哪一个?欢迎在评论区聊聊。
了解 ZenovaConnect 完整方案