第64章 量化数据工程:时序数据库与大规模数据架构¶
补充章节:Quant Data Engineering: Time-Series Databases & Big Data Architecture(原书出版后的市场发展)
在第60章中,我们讨论了如何科学地采样数据(Dollar Bars);在第63章中,我们讨论了如何物理地获取数据(光纤/微波)。现在,我们面临一个更实际的工程挑战:如何存储、管理和极速查询这些海量数据?
对于高频量化团队而言,数据不仅是石油,更是洪流。纳斯达克每天产生数十亿条消息;加密货币市场的 L2/L3 数据量更是呈指数级增长。传统的某些关系型数据库(如 MySQL/PostgreSQL)在处理这种高吞吐、只追加(Append-only)的时序数据时,性能会迅速崩溃。本章将深入探讨量化数据工程的核心——时序数据库(TSDB),并对比 KDB+ 与现代开源方案。
64.1 数据的形态:Tick, Bar, and Alt¶
量化数据具有独特的属性,这些属性决定了其存储架构的特殊性,也解释了为什么通用数据库在此场景下往往力不从心:
1. 极高写入频率:Binance 的 WebSocket 推送可能达到每秒 10 万次更新。
2. 几乎不修改:历史行情一旦发生,就是不可变的(Immutable)。
3. 时间主键:几乎所有的查询都是基于时间范围的(SELECT * FROM ticks WHERE time > t1 AND time < t2)。
4. 列式计算:我们通常计算一列数据的均值(MA)或方差(StdDev),而不是查询单行记录。
5. 多维度查询:按交易所、交易对、时间粒度进行组合过滤和聚合是最常见的查询模式。
6. 数据量级跨度大:从分钟级 K 线(每天数千行)到 L2 逐笔委托(每天数十亿行),同一团队往往需要处理跨越六个数量级的数据规模。
64.2 皇冠上的明珠:KDB+/q¶
在华尔街的顶级投行和对冲基金(如 Goldman Sachs, Morgan Stanley, Citadel),KDB+ 是绝对的统治者。它不仅仅是一个数据库,更是一种信仰。
64.2.1 什么是 KDB+?¶
KDB+ 是由 KX Systems 开发的高性能列式时序数据库。它内置了一种极其精简(甚至晦涩)的编程语言——q。
64.2.2 为什么它这么快?¶
- 列式存储(Columnar Storage):数据按列存储在内存中。计算 VWAP 时,CPU 只需要加载价格列和数量列,极大提高了缓存命中率。
- 向量化计算(Vectorization):q 语言是数组导向的(Array Oriented)。
price * size这一行代码,底层直接调用 SIMD 指令集并行计算整个数组,比循环快几个数量级。 - 内存映射(Memory Mapping):KDB+ 将磁盘文件直接映射到内存地址空间。操作系统负责按需加载页面,数据库本身几乎没有 I/O 管理开销。
64.2.3 缺点¶
- 昂贵:据业界通常报告,许可证费用约为每年数十万美元起。
- 学习曲线陡峭:q 语言的代码可读性极差(被称为"Write-only language")。
- 例子:计算移动平均
mavg:{(x#0.0),x_avg x#y}。
- 例子:计算移动平均
64.3 主流时序数据库性能基准对比¶
选择时序数据库时,性能基准是决策的核心依据。以下对比基于公开的 benchmark 报告和社区实测数据(测试环境:64 核 CPU、256GB 内存、NVMe SSD):
| 指标 | KDB+ | ClickHouse | DolphinDB | TimescaleDB |
|---|---|---|---|---|
| 写入吞吐 | 1000万行/秒 | 500万行/秒 | 800万行/秒 | 50万行/秒 |
| 点查询延迟 | < 1ms | 5-10ms | 2-5ms | 10-50ms |
| 聚合查询(1亿行 VWAP) | 0.3s | 0.8s | 0.5s | 5s |
| 压缩比(tick 数据) | 5:1 | 10:1 (ZSTD) | 8:1 | 4:1 |
| 并发查询支持 | 弱(单线程查询) | 强(MPP 架构) | 中(流计算优先) | 强(PostgreSQL 生态) |
| SQL 兼容性 | 无(q 语言) | 类 SQL | 类 SQL + 脚本 | 完全 SQL |
| 许可成本 | $$$$(数十万美元/年) | 开源免费 | $$$(按核心定价) | 开源免费 |
| 典型用户 | Goldman, Citadel | 加密量化基金 | 国内券商/私募 | 中低频团队 |
选型建议:预算充裕且追求极致查询性能的传统 HFT → KDB+;TB 级历史数据的盘后分析和因子挖掘 → ClickHouse;需要库内实时计算且团队以中文为主 → DolphinDB;希望利用 PostgreSQL 生态且频率不高 → TimescaleDB。
64.3.1 10亿+ Tick 数据的分区与索引策略¶
当 Tick 数据规模突破 10 亿行(约半年的全市场 L2 数据),存储和查询策略必须精心设计:
时间分区(Time Partitioning)。 按天或按小时分区是最基础的策略。每个分区对应磁盘上一个独立的文件或目录,查询时只需扫描相关分区,避免全表扫描。对于加密市场(24/7 交易),推荐按小时分区;对于股票市场,按天分区即可。
符号分片(Symbol Sharding)。 在时间分区的基础上,对交易对/股票代码进行二级分片。例如,/data/2024/03/15/BTC-USDT/ 和 /data/2024/03/15/ETH-USDT/ 各自独立存储。这样查询单个标的的历史数据时,只需读取该标的的分片,IO 效率提升数量级。
列式索引与物化视图。 对高频查询的列(如时间戳、价格、交易方向)建立排序索引。对常用的聚合查询(如 1 分钟 K 线、5 分钟 VWAP)预计算物化视图,以空间换时间。ClickHouse 的 ORDER BY (symbol, timestamp) 和 DolphinDB 的 sortColumns 机制均原生支持这一模式。
64.3.2 实时流处理架构¶
现代量化数据架构不仅要处理历史数据,还必须实时消化行情流。典型的实时数据管道:
交易所 WebSocket → Feed Handler (Rust/C++)
→ Kafka/Redpanda (消息队列, 持久化 + 多消费者)
→ 消费者1: Flink/Bytewax (流计算: 实时因子, K线聚合)
→ TSDB (ClickHouse/DolphinDB)
→ 消费者2: 策略引擎 (直接订阅实时行情)
→ 消费者3: 监控系统 (延迟监控, 数据质量告警)
Kafka vs Redpanda:Kafka 是流处理的事实标准,但 JVM 的 GC 停顿在极端情况下可能引入毫秒级延迟抖动。Redpanda 是用 C++ 重写的 Kafka 兼容替代品,尾延迟更低(P99 < 1ms vs Kafka 的 ~5ms),在延迟敏感的量化场景中越来越受欢迎。
Bytewax:基于 Rust 的 Python 流处理框架,允许用 Python 编写流计算逻辑,底层由 Rust 的 Timely Dataflow 引擎驱动,兼顾了开发效率和运行性能。适合量化团队快速实现实时因子计算管道。
64.4 现代挑战者:开源与云原生¶
随着技术的发展,越来越多的新兴基金开始转向现代开源或云原生方案。KDB+ 的高昂成本和封闭生态促使社区涌现出一批强劲的替代者,它们在特定场景下已经能够匹敌甚至超越 KDB+ 的性能。
64.4.1 ClickHouse¶
源自 Yandex 的 OLAP 数据库,现已成为加密量化圈的新宠。 * 优势:极致的压缩率(ZSTD)和惊人的聚合查询速度。处理 TB 级数据毫无压力。支持物化视图实时聚合,可在写入时自动计算 K 线和 VWAP。 * 场景:适合存储全市场的深度数据(Order Book Depth)和逐笔成交(Trades),用于盘后分析和因子挖掘。 * 注意事项:ClickHouse 的点查询(单行 lookup)性能较弱,不适合作为实时交易系统的查询后端。其优势在于批量分析,而非在线服务。
64.4.2 DolphinDB¶
国产高性能时序数据库,语法类似 SQL + Python,内置了大量金融函数(如 wavg, mavg)。
* 优势:集成了计算引擎,可以在数据库内部直接进行因子计算和流处理,减少了数据搬运。内置的流计算引擎支持滑动窗口、会话窗口等多种窗口模式。
* 场景:适合作为实时行情中心(Tick Plant)和回测数据源。国内多家头部券商和私募已将其作为核心数据平台。
* 注意事项:商业许可按 CPU 核心数定价,大规模集群的成本不可忽视。社区版存在功能限制。
64.4.3 TimescaleDB¶
基于 PostgreSQL 的时序扩展,以 Hypertable 概念自动实现时间分区。 * 优势:完全兼容 SQL 和 PostgreSQL 生态(pgvector、PostGIS 等扩展可无缝叠加)。对于已经熟悉 PostgreSQL 的团队,几乎零学习成本。 * 场景:适合中低频策略团队,或者作为元数据(Metadata)管理系统。也常用于存储策略运行日志和绩效归因数据。 * 注意事项:在 TB 级数据和高并发写入场景下,性能与专用 TSDB 仍有差距。适合作为"够用"的通用方案,而非极致性能方案。
64.5 数据湖仓(Data Lakehouse)与非结构化数据¶
除了行情数据,现代量化还依赖另类数据(Alternative Data):新闻、推特情绪、链上交易记录(On-chain Data)。
- S3 + Parquet/Arrow:最通用的架构。将所有历史数据存储为 AWS S3 上的 Parquet 文件。Parquet 的列式编码(Dictionary Encoding、Run-Length Encoding)对重复性高的金融数据尤其高效,压缩比可达 10:1 以上。
- Apache Arrow:一种跨语言的内存数据格式。Rust 读取 Parquet -> Arrow 内存格式 -> Python (Polars/Pandas) 零拷贝读取。这是目前最高效的跨语言数据管道。
- Delta Lake / Apache Iceberg:在 Parquet 之上增加 ACID 事务支持和时间旅行(Time Travel)能力。对于需要回溯历史数据版本(例如修正了某个数据源的错误后,仍能复现旧版本的回测结果)的团队,这类表格式(Table Format)正在成为标准选择。
64.6 实时行情中心(Tick Plant)架构¶
一个成熟的量化数据架构通常包含以下组件:
- Feed Handler (C++/Rust):连接交易所 WebSocket/FIX,解析二进制流,标准化数据格式。Feed Handler 通常采用无锁队列(Lock-free Queue)将数据推送给下游,以避免多线程竞争引入的延迟抖动。
- Ticker Plant (TP):内存数据库,存储当天的实时数据,供策略订阅。TP 是整个架构的"心脏",通常部署在专用的高内存服务器上,数据按 symbol 哈希分片到不同的进程中。
- Real-time Database (RDB):将 TP 的数据实时写入磁盘日志(Write-Ahead Log),防止断电丢失。RDB 通常采用顺序写入模式,充分利用 NVMe SSD 的顺序写入带宽。
- Historical Database (HDB):每天收盘后(或加密市场中按固定周期),将 RDB 的数据压缩、分片、归档,供历史回测使用。HDB 的查询模式以大范围扫描为主,列式压缩格式在此场景下优势最大。
这一架构最初由 KDB+ 社区提出并标准化,如今已被各类 TSDB 平台广泛借鉴。关键设计原则是数据分层:热数据(当天)驻留内存以保证最低延迟,温数据(近期)保留在高速 SSD 上,冷数据(历史)归档至对象存储(S3)或压缩磁盘阵列。
主要参考资料¶
- Designing Data-Intensive Applications (Martin Kleppmann, 2017) — 系统梳理分布式数据库、流处理与数据管道的架构原则,是量化数据工程师的必读经典
- KDB+/q for Mortals (Jeffry A. Borror) — KDB+ 官方推荐的入门教程,涵盖 q 语言语法与时序数据查询模式
- Apache Parquet Specification (Apache Software Foundation) — Parquet 列式存储格式的技术规范,理解压缩编码与谓词下推的权威文档
- ClickHouse Documentation: Column-Oriented Database Management (ClickHouse Inc.) — ClickHouse 架构设计与 OLAP 查询优化的官方技术参考
- Building a Quantitative Data Infrastructure (Quantlib/OpenGamma 技术博客系列) — 面向量化团队的数据管道设计实践案例
- DolphinDB Tutorials and Use Cases (DolphinDB 官方文档) — 金融时序数据建模、流计算与因子库设计的最佳实践
- Streaming Systems (Tyler Akidau et al., 2018) — 流处理系统的理论基础,涵盖窗口、水印与 Exactly-Once 语义
- The Art of Multiprocessor Programming (Maurice Herlihy & Nir Shavit) — 无锁数据结构与并发编程的经典教材,Feed Handler 开发的理论基础