一、规模变化会改变设计
一个 20MW 分布式场站,测点通常是 3000 到 8000 个:逆变器十几到几十台,组串数百串,加上气象站、关口表、并网点电表。按 1 分钟采集频率算:
- 单站日增记录 5000 × 1440 ≈ 720 万条
- 50 个站合计约 3.6 亿条
- 按每条约 200 字节估算,日增存储约 72 GB
单站时这些数字都不成问题,用一张表加索引就能跑。扩到 50 个站,问题会按顺序出现三次:写入先扛不住,然后是查询,最后是成本。这也是光伏集中监控平台的数据层要单独设计的原因。
二、写入:先入队,再批量落库
为什么不能直写。 分钟级采集的时间戳高度集中,整分钟后的 5 到 15 秒是写入峰值,瞬时并发可能是均值的 3 到 5 倍。采集服务直接写库,高峰期会把连接池占满,表现是采集延迟升高、部分批次超时重试,数据反而更乱。
做法。 采集侧只负责把数据投递到消息队列,落库由独立消费端按批次完成。消费端有两个参数要调:批量大小和提交间隔。批量太小起不到削峰作用,太大会放大单次失败的影响面,实践上按「单批 1000 到 5000 条、间隔 200 到 500 毫秒」起步,再按实际压力调整。
分区键的选择比分区数量更重要。 常见错误是按采集时间做分区键,结果是所有写入都落在当前时间分区上,形成单点热点,分区再多也没用。正确的键是「站点 + 设备」,让写入按设备散开,时间只作为分区裁剪条件。
-- 分区键用站点与设备,时间只做裁剪
CREATE TABLE measurement (
ts timestamptz NOT NULL,
site_id int NOT NULL,
device_id int NOT NULL,
point_code text NOT NULL,
value double precision,
quality smallint
) PARTITION BY HASH (site_id, device_id);
幂等不能省。 弱网场站断连后走本地缓存补传,如果服务端不做去重,补传数据会和实时数据叠加,同一时段被计量两次。去重键用「设备 + 测点 + 时间戳」三元组,写入走 upsert。
三、查询:降采样比加索引有效
集中监控有三类查询,特征完全不同:
- 首页最新值:范围小、频率高,要的是最新一条
- 月报聚合:范围大、频率低,要的是区间汇总
- 故障复盘:范围小、要求原始精度
把三类请求打到同一张原始表上,长尾查询会把连接池占满,表现是「页面偶尔转圈」,从日志里很难定位到具体语句。
处理办法是分档降采样:最近一小时保留原始点,一天内按分钟聚合,更早按小时或天聚合。查询侧按时间跨度路由到不同粒度,前端不直接请求原始点。
SELECT time_bucket('1 hour', ts) AS bucket,
device_id,
avg(value) AS avg_value,
max(value) AS max_value,
count(*) AS sample_count
FROM measurement
WHERE site_id = :site_id
AND ts >= :start AND ts < :end
GROUP BY bucket, device_id
ORDER BY bucket;
顺带说一句,降采样表要保留 sample_count,否则看不出聚合结果是由多少条原始点算出来的,异常时无法判断是数据缺失还是数值本身异常。
四、告警:三级收敛
50 个站的原始告警一天能到上千条。没有收敛,值班人员一周内就会关掉通知。
抑制。 父设备离线时,其下所有子设备告警置为抑制,不推送但保留明细。一次通信中断可能牵动几十台设备,收敛后只剩一条根因。
聚合。 同一汇流箱、同一支路下的同类告警合并为一条根因事件,子告警作为明细挂载。
分级。 按影响范围定级:影响全站出力的置为紧急,影响单台设备的置为一般,仅数据质量异常的置为提示。首页默认只显示紧急项。
rule:
when: dc_current < group_avg * 0.6
for: 15m
scope: string
severity: warning
suppress_when: parent_offline
aggregate_by: combiner_box
抑制只应作用于有明确父子关系的告警。抑制期间子告警保留为明细而不是丢弃,父设备恢复后重算,并单独记录抑制事件,供事后复盘。
五、存储:冷热分层
不同形态的数据放在一起存,成本和查询性能都会受影响。量测序列入时序库;告警、工单这类带生命周期的对象入关系库;热成像原图、IV 曲线原始文件入对象存储,库里只留索引和缩略图路径。
时序数据建议按时间做生命周期策略:原始数据保留 1 到 3 年,聚合数据长期保留。具体年限受监管报送要求和存储成本双重约束。
六、三个容易踩的坑
设备时钟漂移。 逆变器本地时钟与服务器时间常有分钟级偏差,部分老机型断电后归零。处理方式是采集侧同时记录设备时间与网关时间,服务端以网关时间为准,偏差单独作为数据质量指标监控。不处理这一步,峰谷时段统计会算错,且错的方向随机,报表上看不出规律。
补数窗口失控。 补传不能无条件接受。超过设定窗口的迟到数据应进入异常队列,不直接参与实时统计,否则历史区间会不断被改写,报表前后对不上。
降采样没有回填。 降采样任务是批处理,失败重跑时若不做幂等,会出现重复聚合。聚合表的主键要能准确对应到「粒度 + 设备 + 时间桶」,重跑时才能覆盖而不是追加。
七、小结
光伏集中监控平台在测点规模扩大之后,数据层的改动顺序基本固定:先解决写入的削峰与幂等,再解决查询的分档降采样,最后处理存储分层与告警收敛。跳过前两步直接做分析,通常得到一堆无法验证的结论。

常见问题
问:消息队列一定要引入吗?
答:取决于峰值倍数和可接受的丢数风险。峰值不超过均值 2 倍、且允许采集侧短暂重试的场景,可以先用进程内缓冲加批量提交;峰值倍数高或不允许丢数,队列更稳。
问:降采样的粒度怎么定?
答:按查询习惯定,不按存储成本定。首页看的是最近几小时,月报看的是整月趋势,故障复盘才需要原始点。三个粒度分别覆盖即可,再多就是浪费。
问:分区数量越多越好吗?
答:不是。分区过多会增加元数据开销和查询计划时间。分区键选对之后,按「单分区数据量落在几百万行」这个量级反推分区数即可。