第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 数据清洗:脏数据比没数据更可怕

行情数据不是完美的。交易所偶尔会发错数据,网络抖动会导致重复或丢失。如果不做清洗,策略可能会被带偏。

我总结了几种常见的脏数据场景:

  1. 重复数据:同一笔 Tick 被推送了两次
  2. 异常价格:价格突然跳变,比如从 100 跳到 10000
  3. 时间戳错乱:数据的时间戳比当前时间晚了几分钟
  4. 缺失数据:某段时间内完全没有数据

清洗策略我一般这样设计:

-- 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 本章知识体系

下面这张图,是我对本章内容的整体梳理。你可以把它当作一个参考框架:

订单流数据存储与管理知识体系 时序数据库 数据库选型 ClickHouse vs InfluxDB 写入性能 / 查询能力 压缩比 / 部署复杂度 数据压缩 时间戳差值编码 列式存储 / 字典编码 分区策略 / 索引粒度 数据清洗 去重 / 异常价格过滤 时间戳校验 缺失数据补全 备份与恢复 全量备份 / 增量备份 实时同步 / 恢复演练

说白了,数据存储与管理这件事,没有银弹。你得根据自己的业务场景,选择合适的数据库、设计合理的压缩策略、做好清洗规则、建立可靠的备份机制。每一步都踩过坑,才能把系统做得稳。

我个人觉得,数据层是交易系统的地基。地基不稳,上面盖再漂亮的策略大楼,早晚要塌。希望这一章的内容,能帮你少走一些弯路。


无相订单流研究社 微信Lucian808555