3、数据存储设计:HDF5、Parquet、SQLite存储方案对比,时间序列数据库选型
做订单簿回溯,数据存储这块儿,说实话,我踩过的坑比赚到的钱还多。
一开始我图省事,直接往CSV里怼。结果呢?一个月的Level2数据,文件几十个G,加载一次要等一首歌的时间。后来我学乖了,开始认真研究存储方案。
今天咱们就聊聊,订单簿这种高频时序数据,到底该怎么存。
3.1 存储方案三剑客:HDF5、Parquet、SQLite
这三样东西,我都在生产环境里用过。各有各的脾气,咱们一个一个说。
3.4.1 HDF5:科学计算的老大哥
HDF5,全称Hierarchical Data Format。说白了,就是一种能塞下海量数据的文件格式。我最早接触它是在做气象数据分析的时候,后来发现拿来做订单簿存储,简直绝配。
优点:
- 速度快:读取大块连续数据时,HDF5几乎是碾压级别的。我测试过,读取100万条订单簿快照,HDF5比CSV快了将近20倍。
- 支持压缩:默认的gzip压缩,能把数据体积压到原来的1/5左右。磁盘空间省了,IO压力也小了。
- 层次结构:你可以把数据组织成类似文件系统的结构。比如 /orderbook/btc_usdt/2024/01/15,这样查询起来非常直观。
缺点:
- 并发写入差:HDF5在单线程写入时表现很好,但多线程同时写同一个文件,很容易出问题。我曾经在实盘回测时踩过这个坑,两个进程同时写,结果文件直接损坏了。
- 生态相对封闭:虽然Python有h5py和pytables,但其他语言的支持就没那么好了。如果你团队里有人用Java或C++,可能会有点头疼。
我的建议:如果你做的是单机回测,数据量在几十GB以内,HDF5是性价比最高的选择。尤其是需要频繁读取全量数据做分析时,它的优势很明显。
3.4.2 Parquet:大数据生态的宠儿
Parquet是Hadoop生态里出来的格式。我一开始觉得它太重了,直到有一次需要处理TB级别的订单簿数据,才发现它的好。
优点:
- 列式存储:订单簿数据有很多字段,但很多时候你只需要其中几列。比如我只想看买卖价差,Parquet可以只读取那两列,IO开销小得惊人。
- 压缩率极高:同样的数据,Parquet用snappy压缩后,体积只有HDF5的一半左右。我存过一年的BTC订单簿数据,HDF5用了200GB,Parquet只用了110GB。
- 生态好:Spark、Pandas、DuckDB都原生支持Parquet。跨平台、跨语言,基本没有障碍。
缺点:
- 小文件性能差:Parquet是为大文件设计的。如果你把数据切成很多小文件(比如每个文件只有几MB),读写效率会急剧下降。我见过有人把每秒的订单簿快照存成单独的文件,结果查询时慢到怀疑人生。
- 写入开销大:每次写入Parquet,都需要先缓存一批数据,然后一次性刷盘。不适合做实时写入。
避坑指南:我曾经把Parquet文件切得太小,导致查询时频繁打开关闭文件句柄,系统直接卡死了。后来我改成每小时合并一次文件,问题就解决了。记住,Parquet文件最好在100MB以上。
3.4.3 SQLite:轻量级的关系数据库
SQLite,很多人觉得它就是个玩具。但说实话,在数据量不大(几GB以内)的场景下,它比很多大数据库都好用。
优点:
- 零配置:不需要安装服务,不需要配置端口,一个文件搞定。我经常在开发环境里用它做原型验证。
- 支持SQL:查询灵活,可以按时间范围、价格区间、买卖方向任意组合。比如「查询2024年1月15日14:00到14:05之间,卖一价大于50000的订单簿快照」,一条SQL就搞定了。
- 事务支持:写入时保证原子性,不会出现数据损坏的问题。
缺点:
- 写入性能瓶颈:SQLite是单线程写入的。如果你每秒要写入几千条订单簿快照,它会成为瓶颈。我试过,超过每秒500次写入,延迟就开始飙升了。
- 不适合海量数据:当数据量超过10GB时,SQLite的查询性能会明显下降。索引维护的成本也越来越高。
注意:SQLite不适合做高频写入。如果你需要实时记录每一笔订单簿变化,建议用其他方案。但如果你只是做离线分析,SQLite是个不错的选择。
3.2 三种方案对比一览
我整理了一张表,方便你快速对比:
| 特性 | HDF5 | Parquet | SQLite |
|---|---|---|---|
| 读取速度(全量) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 读取速度(条件查询) | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 写入速度 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| 压缩率 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 并发支持 | ⭐ | ⭐⭐⭐ | ⭐⭐ |
| 生态兼容性 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 适用场景 | 单机大文件分析 | 大数据分布式处理 | 小规模灵活查询 |
3.3 时间序列数据库选型
如果你觉得文件格式不够用,想要一个真正的数据库来管理订单簿数据,那就得考虑时序数据库了。
我试过几个主流的,说说我的感受。
3.3.1 InfluxDB
InfluxDB,时序数据库里的老牌选手。我最早用它来存股票Tick数据。
- 优点:写入速度极快,查询语法简单(类SQL),自带数据保留策略(自动删除旧数据)。
- 缺点:集群版要收费,单机版数据量大了之后性能下降明显。我试过存了半年的数据后,查询延迟从毫秒级变成了秒级。
3.3.2 TimescaleDB
TimescaleDB,基于PostgreSQL的时序数据库。说白了,就是在关系数据库上加了时序优化。
- 优点:完全兼容PostgreSQL,可以用所有PG的生态工具。支持复杂的JOIN查询,适合做订单簿和交易数据的关联分析。
- 缺点:写入性能不如InfluxDB,尤其是在高并发场景下。我测试过,同样硬件条件下,TimescaleDB的写入吞吐量只有InfluxDB的60%左右。
3.3.3 ClickHouse
ClickHouse,列式存储的OLAP数据库。我最近两年一直在用,越来越喜欢。
- 优点:查询速度极快,尤其是做聚合分析。比如计算每分钟的平均买卖价差,ClickHouse能在毫秒级返回结果。压缩率也很高,我存了一年的订单簿数据,原始数据大概5TB,ClickHouse只用了800GB。
- 缺点:不适合单条数据的频繁更新。订单簿数据是追加写入的,所以这个问题不大。但如果你需要频繁修改历史数据,ClickHouse就不太合适了。
我的选择:目前我在生产环境用的是ClickHouse。原因很简单——查询快、压缩高、生态好。配合Grafana做可视化,效果非常棒。但如果你需要事务支持或者复杂的关联查询,TimescaleDB可能更合适。
3.4 核心逻辑:存储方案选型决策流程
说了这么多,到底该怎么选?我画了一张图,帮你理清思路:
嗯,这张图基本概括了我的选型思路。你想想看,如果你的数据量只有几个GB,用SQLite做灵活查询,配合HDF5做批量分析,完全够用了。但如果数据量上了百GB,甚至TB级别,那就老老实实用Parquet或者ClickHouse吧。
我个人习惯是:开发阶段用SQLite,快速验证想法;生产环境用ClickHouse,保证性能和稳定性。中间的数据转换,用Parquet作为中间格式,方便在不同系统之间流转。
好了,存储方案这块儿就聊到这儿。记住一点:没有最好的方案,只有最适合你场景的方案。多试试,多踩坑,慢慢就有感觉了。