第21章:数据存储与管理——时序数据库应用、数据压缩、数据清洗、数据备份与恢复
做订单流交易系统,最头疼的问题是什么?
我个人觉得,不是策略怎么写,而是数据怎么管。你想想看,Tick 级别的行情数据,一天下来就是几个 GB。一个月呢?一年呢?如果不把数据存储这块设计好,系统迟早会崩。
这一章,我就跟你聊聊时序数据库在订单流系统里的实战经验。包括 ClickHouse 和 InfluxDB 怎么选、数据怎么压缩、脏数据怎么清洗、以及备份恢复的那些坑。
21.1 为什么订单流系统离不开时序数据库?
传统的关系型数据库,比如 MySQL,存个用户信息、订单记录还行。但你要用它存毫秒级的行情快照?那基本是找罪受。
订单流数据有几个特点:
- 写入频繁:每秒成千上万条 Tick 数据
- 时间敏感:所有查询都围绕时间窗口
- 只增不改:历史数据几乎不会修改
- 数据量大:单日存储量轻松上 GB
时序数据库就是为这种场景设计的。它把时间戳作为主索引,写入速度快,压缩比高,查询效率也远超普通数据库。
核心观点:订单流系统的数据层,时序数据库是标配。别想着用 MySQL 硬扛,那不是技术问题,是架构问题。
21.2 ClickHouse vs InfluxDB:我该怎么选?
这两个是目前最主流的时序数据库。我在项目中都用过,说说我的感受。
| 对比维度 | ClickHouse | InfluxDB |
|---|---|---|
| 写入性能 | 极高,批量写入可达百万行/秒 | 高,单机写入稳定 |
| 查询能力 | 支持标准 SQL,功能强大 | 类 SQL 语法,功能有限 |
| 压缩比 | 极高,通常 5-10 倍 | 较高,通常 3-5 倍 |
| 部署复杂度 | 中等,需要调优 | 简单,开箱即用 |
| 适用场景 | 大规模分析、复杂聚合 | 实时监控、简单查询 |
我个人的建议是:
- 如果你要做深度分析,比如回测、因子计算,选 ClickHouse。它的 SQL 支持太强了,能省很多代码。
- 如果你只是实时监控,比如看当前盘口深度、成交变化,选 InfluxDB。部署简单,运维成本低。
小技巧:我见过不少团队两个都用。InfluxDB 做实时展示,ClickHouse 做历史分析。数据通过消息队列同步,各取所长。
21.3 数据压缩:别让存储成本吃掉你的利润
做量化交易,数据存储是一笔不小的开销。尤其是 Tick 数据,一天不压缩,硬盘很快就满了。
时序数据库的压缩机制,说白了就是利用数据的规律性。比如:
- 时间戳差值编码:相邻 Tick 的时间差通常很小,存差值比存完整时间戳省得多
- 列式存储:同一列的数据类型相同,压缩算法可以针对优化
- 字典编码:对于重复值多的字段,比如交易所代码,用字典映射
以 ClickHouse 为例,我常用的建表语句是这样的:
CREATE TABLE order_flow.tick_data
(
symbol String,
timestamp DateTime64(3),
price Float64,
volume UInt64,
bid_price Float64,
ask_price Float64,
bid_volume UInt64,
ask_volume UInt64
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(timestamp)
ORDER BY (symbol, timestamp)
SETTINGS index_granularity = 8192;
这里有几个关键点:
- PARTITION BY:按月分区,方便管理历史数据
- ORDER BY:按品种和时间排序,查询效率最高
- index_granularity:控制索引粒度,默认 8192 行一个索引
注意:我曾经遇到过一个问题——分区太多导致查询变慢。比如按天分区,一个月 30 个分区,查询时反而要合并更多数据。按月分区是比较平衡的选择。
21.4 数据清洗:脏数据比没数据更可怕
行情数据不是完美的。交易所偶尔会发错数据,网络抖动会导致重复或丢失。如果不做清洗,策略可能会被带偏。
我总结了几种常见的脏数据场景:
- 重复数据:同一笔 Tick 被推送了两次
- 异常价格:价格突然跳变,比如从 100 跳到 10000
- 时间戳错乱:数据的时间戳比当前时间晚了几分钟
- 缺失数据:某段时间内完全没有数据
清洗策略我一般这样设计:
-- ClickHouse 去重示例
INSERT INTO order_flow.tick_data_clean
SELECT DISTINCT *
FROM order_flow.tick_data_raw;
-- 异常价格过滤
INSERT INTO order_flow.tick_data_clean
SELECT *
FROM order_flow.tick_data_raw
WHERE price BETWEEN 0.01 AND 100000
AND volume > 0;
嗯,这里要注意:去重不能只看整行数据。有时候两笔 Tick 价格一样,但时间戳差了 1 毫秒,那是正常数据。我一般用 (symbol, timestamp) 作为唯一键来判断重复。
避坑指南:我曾经因为没做时间戳校验,导致回测结果完全错误。后来加了一个规则——如果某条数据的时间戳比前一条还早,直接丢弃。这个简单的规则救了我好几次。
21.5 数据备份与恢复:别等到丢了才后悔
做交易系统,数据就是命。硬盘坏了、误删了、被攻击了……任何意外都可能导致数据丢失。
备份策略我建议分三层:
| 备份层级 | 频率 | 存储位置 | 用途 |
|---|---|---|---|
| 全量备份 | 每周一次 | 异地存储 | 灾难恢复 |
| 增量备份 | 每天一次 | 本地 + 云 | 日常恢复 |
| 实时同步 | 实时 | 备用数据库 | 高可用 |
ClickHouse 的备份命令很简单:
# 全量备份
clickhouse-backup create full_backup_20240101
# 恢复
clickhouse-backup restore full_backup_20240101
InfluxDB 的备份方式:
# 备份
influxd backup -portable /path/to/backup
# 恢复
influxd restore -portable /path/to/backup
重要提醒:备份一定要做恢复演练。我见过有人备份了两年,结果恢复时发现文件损坏。定期检查备份文件的完整性,这个步骤不能省。
21.6 本章知识体系
下面这张图,是我对本章内容的整体梳理。你可以把它当作一个参考框架:
说白了,数据存储与管理这件事,没有银弹。你得根据自己的业务场景,选择合适的数据库、设计合理的压缩策略、做好清洗规则、建立可靠的备份机制。每一步都踩过坑,才能把系统做得稳。
我个人觉得,数据层是交易系统的地基。地基不稳,上面盖再漂亮的策略大楼,早晚要塌。希望这一章的内容,能帮你少走一些弯路。