数据存储与解析:时序数据库选型与优化
存储层是巡检系统的基石。选错了,后面所有折腾都是白费。我见过不少项目,前期图省事用通用数据库存时序数据,三个月后查询慢得像蜗牛,最后不得不推倒重来。
选型对比:InfluxDB vs TimescaleDB
目前工业监控领域,时序数据库基本就是两派:InfluxDB 和 TimescaleDB。前者是原生时序,后者是 PostgreSQL 扩展。到底选哪个?我个人习惯先看两个关键指标:写入性能和压缩比。
| 对比维度 | InfluxDB | TimescaleDB |
|---|---|---|
| 写入吞吐 | 单节点 > 100万点/秒 | 单节点 > 50万点/秒 |
| 压缩比 | 1:10 ~ 1:15 | 1:5 ~ 1:8 |
| SQL 兼容 | 类 SQL(Flux) | 完整 SQL(PG 生态) |
| 集群能力 | 企业版 | 开源 + Patroni |
我的建议:如果巡检点超过 5000 个,每秒写入超过 10 万点,优先考虑 InfluxDB。反之,团队 SQL 能力较强、需要跟业务系统联查的,选 TimescaleDB。
数据保留策略
很多新手上来就把所有数据永久保留,结果磁盘爆了。其实大多数工业场景,原始数据保存 30 天就够用了。
我之前帮一个钢厂做过改造,他们的温控数据原来存三年,查询响应时间 30 秒以上。后来改成:原始数据 7 天,聚合数据(每分钟均值)90 天,统计摘要(每天)3 年。查询快了 10 倍,存储节省了 80%。
InfluxDB 的保留策略(RP)
-- 创建 30 天保留策略
CREATE RETENTION POLICY "rp_30d" ON "iot_metrics" DURATION 30d REPLICATION 1 DEFAULT
-- 自动清理过期的原始数据
ALTER RETENTION POLICY "rp_30d" ON "iot_metrics" SHARD DURATION 1d
小技巧:Shard 持续时间建议设成数据保留期的 1/30。比如保留 30 天,Shard 就设 1 天。这样 InfluxDB 可以按天清理,效率最高。
TimescaleDB 的保留策略
TimescaleDB 用 Hypertable + 数据保留 Job 实现类似效果。
-- 设置自动保留(保留 7 天)
SELECT add_retention_policy('raw_readings', INTERVAL '7 days', if_not_exists => true);
-- 查看保留策略状态
SELECT * FROM timescaledb_information.jobs
WHERE application_name LIKE '%retention%';
注意!TimescaleDB 的保留策略是基于数据写入时间的。如果设备写了未来的时间戳,数据会被提前删除。我遇到过这种坑,后来在后端强制检查了时间戳合法性。
数据压缩:存储成本的关键
时序数据的价值随时间递减。你想想看,一个阀门的开度数据,三个月前的和昨天的,哪个更重要?所以,压缩策略必须按时间分层。
InfluxDB 压缩原理
InfluxDB 内置的压缩算法针对整数和浮点数做了极致优化。说白了,它能把多个时间点的数据合并成一个差值编码。
-- 查看某个 shard 的压缩比
SHOW SHARDS
-- 留意 "Compressed Ratio" 列,通常在 10~15 倍之间
如果发现压缩比低于 5,说明你的数据中可能混入了文本类型 tag。tag 的重复值不多,压缩效果就差。
TimescaleDB 压缩
TimescaleDB 的压缩需要手动启用,但可以按 Chunk 策略来。
-- 启用压缩
ALTER TABLE raw_readings SET (timescaledb.compress);
-- 设置自动压缩策略(超过 7 天的 chunk 自动压缩)
SELECT add_compression_policy('raw_readings', INTERVAL '7 days');
-- 查看压缩后的空间节省
SELECT pg_size_pretty(before_compression_total_bytes) as before,
pg_size_pretty(after_compression_total_bytes) as after,
round(100 - (100 * after_compression_total_bytes::numeric / nullif(before_compression_total_bytes, 0)), 3) as pct_saving
FROM hypertable_compression_stats('raw_readings');
实战心得:我试过把压缩策略从 7 天改成 1 天,结果 CPU 负载升高了 30%。后来还是改回 7 天,因为新写入的 chunk 还在持续修改,太早压缩反而会频繁解压重写,得不偿失。
知识体系总览
说了这么多,我画了一张图帮你理清思路。从数据采集到最后清理,每一步都有对应的技术选择。
综合配置案例
最后,给一个我在真实项目中用过的配置模板,供你参考。这个配置支撑了 3000 个传感器,每天 2 亿数据点。
-- InfluxDB 生产配置关键参数
[data]
dir = "/data/influxdb/data"
wal-dir = "/data/influxdb/wal"
cache-max-memory-size = "1g"
cache-snapshot-memory-size = "256m"
cache-snapshot-write-cold-duration = "10m"
compact-full-write-cold-duration = "24h"
max-series-per-database = 0
max-values-per-tag = 0
index-version = "tsi1"
[retention]
check-interval = "30m"
-- 保留策略,3 层
CREATE RETENTION POLICY "raw_7d" ON "factory_metrics" DURATION 7d REPLICATION 1 DEFAULT;
CREATE RETENTION POLICY "agg_90d" ON "factory_metrics" DURATION 90d REPLICATION 1;
CREATE RETENTION POLICY "summary_3y" ON "factory_metrics" DURATION 365d * 3 REPLICATION 1;
性能调优:WAL 目录建议放在 SSD 上,数据目录可以放在 HDD。我这样做了之后,写入延迟从 15ms 降到了 3ms,效果很明显。
数据库选型没有银弹,关键是搞清楚你的场景。设备数量?写入频率?查询模式?这些答案直接决定你该选 InfluxDB 还是 TimescaleDB。先把这步想清楚,后面的保留策略、压缩配置才有意义。