第4章:时序数据库选型与设计
各位同学好,今天我们来聊聊风电功率预测系统里一个非常关键的底层组件——时序数据库。说实话,我见过不少项目,算法模型做得漂漂亮亮,结果数据存取的环节拖了后腿,整个系统响应慢得像蜗牛。嗯,这章我们就来把这个坑填上。
4.1 为什么风电系统离不开时序数据库?
风电功率预测,说白了就是跟时间序列数据打交道。风机每秒钟产生的风速、风向、转速、功率数据,都是带时间戳的。你想想看,一个风场几十台风机,一天下来就是几亿条数据。
传统的关系型数据库,比如MySQL,存这种数据其实很吃力。我曾在项目里试过用MySQL存风电数据,结果查询一个月的趋势图,等了十几秒才出来。后来换成时序数据库,同样的查询,毫秒级响应。为什么会这样?因为时序数据库从底层设计上就是为这种场景优化的。
核心观点:时序数据库是风电功率预测系统的数据基石。选对了,事半功倍;选错了,后面全是坑。
4.2 三大时序数据库对比
目前市面上主流的时序数据库,我重点用过三个:InfluxDB、TimescaleDB、TDengine。每个都有自己的脾气,我们来逐个聊聊。
| 特性 | InfluxDB | TimescaleDB | TDengine |
|---|---|---|---|
| 底层存储 | 自研TSM引擎 | 基于PostgreSQL | 自研时序引擎 |
| 写入性能 | 高(单机百万点/秒) | 中(依赖PG优化) | 极高(千万点/秒) |
| 查询语法 | 类SQL(Flux/InfluxQL) | 标准SQL | 类SQL(有限支持) |
| 集群能力 | 企业版支持 | 原生支持 | 原生支持 |
| 学习成本 | 中等 | 低(熟悉PG即可) | 中等 |
| 适用场景 | 中小规模监控 | 需要复杂关联查询 | 大规模工业物联网 |
4.2.1 InfluxDB:灵活但有点“娇气”
InfluxDB是我最早接触的时序数据库。它的数据模型很灵活,tag、field、timestamp三层结构,写起来很顺手。我个人习惯用它做原型验证,因为部署简单,一条命令就能跑起来。
但是,我在项目中遇到过一个问题:InfluxDB的单机版在高并发写入时,容易触发压缩瓶颈。有一次现场数据量突增,写入延迟从毫秒级飙升到秒级,差点影响预测系统的实时性。后来我们加了写入缓冲层才解决。
小技巧:用InfluxDB时,tag的基数不要太大。我建议控制在100万以内,否则索引性能会急剧下降。
4.2.2 TimescaleDB:SQL党的最爱
TimescaleDB本质上是PostgreSQL的一个扩展。如果你团队里都是SQL高手,那选它准没错。标准SQL写起来就是爽,join、子查询、窗口函数随便用。
我记得有一次做风功率预测的特征工程,需要把风速数据和气象预报数据做时间对齐。用TimescaleDB的time_bucket函数,一行SQL就搞定了。换成InfluxDB,得写一堆Flux脚本,麻烦得很。
不过,TimescaleDB的写入性能相比原生时序库还是弱一些。它底层还是PG的那套行存机制,虽然加了自动分区,但写吞吐量上不去。我建议数据量在每天10亿条以下的场景用TimescaleDB,再大就得考虑别的了。
4.2.3 TDengine:国产之光,但生态尚浅
TDengine是涛思数据的产品,我这两年用得比较多。它的设计理念很对我胃口——一个数据采集点一张表,超级表做聚合。这种模型跟风电场景天然契合:每台风机一张子表,整个风场一个超级表。
性能方面,TDengine确实猛。我做过压测,单机写入速度能到每秒800万点,查询一个月的聚合数据,基本在100毫秒以内。而且它对ARM架构支持很好,我们有些边缘节点用树莓派跑TDengine,稳得很。
注意:TDengine的SQL语法跟标准SQL有差异,比如不支持完整的JOIN操作。如果你的查询逻辑特别复杂,可能需要做一层数据预处理。
4.3 数据模型设计
数据模型设计,说白了就是怎么组织你的数据。我总结了一个“三要素”原则:
- 时间戳:统一用UTC时间,避免时区问题。我习惯用毫秒级精度,够用又不浪费存储。
- 标签:风机ID、机组型号、风场ID这些不变的信息。标签会被索引,所以基数要控制好。
- 指标:风速、功率、转速这些数值。指标是实际存储的数据,会做压缩。
举个例子,在TDengine里创建超级表:
CREATE STABLE TABLE wind_turbine (
ts TIMESTAMP,
wind_speed FLOAT,
power_output FLOAT,
rotor_speed FLOAT,
pitch_angle FLOAT
) TAGS (
turbine_id INT,
wind_farm_id INT,
model_type VARCHAR(20)
);
然后每台风机创建一张子表:
CREATE TABLE turbine_001 USING wind_turbine TAGS(1, 101, 'GW-1500');
这样设计的好处是,查询单台风机数据时,直接定位到子表,效率极高。我建议你按这个模式来,别把所有数据塞到一张大表里。
4.4 存储策略与保留策略
风电数据有个特点:越老的数据,价值越低。实时预测用最近一小时的数据,短期预测用最近一周,中长期预测才用到历史数据。所以,没必要把所有数据都存成一份。
我常用的策略是“分层存储”:
- 热数据:最近7天,全精度存储,放在SSD上。
- 温数据:7天到3个月,降采样到1分钟粒度,放在HDD上。
- 冷数据:3个月以上,降采样到10分钟粒度,归档到对象存储。
在InfluxDB里,保留策略(Retention Policy)可以这样配:
CREATE RETENTION POLICY "hot_policy" ON "wind_db" DURATION 7d REPLICATION 1 SHARD DURATION 1h DEFAULT;
CREATE RETENTION POLICY "warm_policy" ON "wind_db" DURATION 90d REPLICATION 1 SHARD DURATION 1d;
TDengine则用自动建库时指定保留天数:
CREATE DATABASE wind_db KEEP 365 DAYS 10 BLOCKS 6;
避坑指南:我曾经在项目里把保留策略设得太短,结果做年度分析时发现历史数据已经被删了。后来我改成“保留+归档”双保险:数据库里保留3个月,同时每天把数据备份到廉价存储里。
4.5 数据压缩与分区
压缩和分区,是时序数据库性能的两大法宝。先说压缩。
时序数据有很强的规律性:风速不会从0突然跳到20,功率曲线也是平滑变化的。利用这个特点,时序数据库可以用差值编码、游程编码等算法,把数据压缩到原始大小的十分之一甚至更小。
我实测过,InfluxDB的压缩比大概在5:1到8:1之间,TDengine能做到10:1以上。你想想看,原来需要100TB的存储,压缩后只要10TB,成本省了多少。
再说分区。分区就是把数据按时间切分成小段,查询时只扫描相关分区,避免全表扫描。我建议按小时或天分区,具体看你的数据量。
在TimescaleDB里,创建分区表:
SELECT create_hypertable('wind_data', 'ts', chunk_time_interval => INTERVAL '1 day');
TDengine默认按10天一个文件块分区,你也可以调整:
CREATE DATABASE wind_db DAYS 10;
我的经验:分区粒度不是越细越好。太细了,分区数量过多,元数据管理开销反而大。一般数据量在每天1亿条以下,按天分区就够了。超过这个量,可以考虑按小时分区。
4.6 本章小结
时序数据库选型,没有银弹。InfluxDB灵活,适合快速原型;TimescaleDB SQL兼容性好,适合复杂查询;TDengine性能强悍,适合大规模部署。我的建议是:先评估你的数据量和查询模式,再决定用哪个。
数据模型设计上,记住“时间戳+标签+指标”的三要素。存储策略要分层,保留策略要留余地。压缩和分区是性能的关键,一定要用好。
嗯,这章就讲到这里。下一章我们会聊数据采集层的设计,包括如何从风机PLC、SCADA系统里高效地拿到数据。到时候见。
公众号:蓝海资料掘金营,微信deep3321