2. ClickHouse基础入门
在分布式行情集群中,ClickHouse之所以能承载每秒百万级的行情快照写入与毫秒级历史回放查询,根源在于它从存储布局到执行引擎都为“批量列式分析”而设计。本节从列式存储原理切入,串联MergeTree引擎族、数据类型、表引擎选择与安装部署,帮助你建立可落地的ClickHouse基础认知。
一、列式存储原理:为什么行情场景天然适配
行情数据具有典型的“宽表、少列查询、高压缩比”特征。以逐笔成交表为例,字段可能包含时间戳、合约代码、最新价、成交量、买卖盘口等数十列,但一次查询往往只关心其中3~5列。行式存储需要把整行数据读入内存再过滤,而列式存储将同一列的值连续存放,查询时只读取涉及的列,I/O量可下降一个数量级。
列式存储还带来两个直接收益:一是同列数据类型一致,压缩算法(如LZ4、ZSTD、Delta、DoubleDelta)能获得极高压缩率,行情历史数据通常可压缩到原大小的1/5~1/10;二是向量化执行,ClickHouse按列批量处理数据块(Block),配合SIMD指令,单核扫描吞吐可达数GB/s。
二、MergeTree引擎族:ClickHouse的存储核心
MergeTree是ClickHouse最核心的表引擎家族,几乎所有生产表都基于它或其派生引擎。其基本工作模型是:写入时按主键排序生成不可变的小数据片段(Part),后台线程持续将小Part合并为大Part,合并过程中完成去重、聚合或替换等语义。
MergeTree家族的关键成员及适用场景如下:
| 引擎 | 核心语义 | 行情场景示例 |
|---|---|---|
| MergeTree | 基础排序合并,无去重 | 原始逐笔流水、日志类行情 |
| ReplacingMergeTree | 按排序键保留最新版本 | 合约最新状态、盘口快照去重 |
| SummingMergeTree | 合并时对数值列求和 | 按分钟聚合的成交量统计 |
| AggregatingMergeTree | 合并时按聚合函数状态合并 | K线OHLC、VWAP等预聚合 |
| CollapsingMergeTree | 按Sign列折叠抵消 | 订单状态变更、撤单抵消 |
选择引擎时先问三个问题:数据是否需要去重?是否需要预聚合?是否需要支持状态撤销?若都不需要,直接用MergeTree;若需要按主键保留最新,用ReplacingMergeTree;若需要增量聚合,用AggregatingMergeTree或SummingMergeTree。
三、数据类型与表引擎选择要点
ClickHouse数据类型直接影响存储与查询性能。行情场景常用类型包括:
- DateTime64(3/6/9):毫秒/微秒/纳秒时间戳,行情时间精度首选。
- Decimal64/Decimal128:精确价格,避免Float精度丢失。
- LowCardinality(String):合约代码、交易所等低基数列,显著降低内存与I/O。
- FixedString(N):定长代码,如交易所编码。
- Array/Tuple:盘口多档买卖价量,适合嵌套结构。
表引擎选择还需关注分区键与排序键。行情表通常按toYYYYMMDD(ts)或toStartOfHour(ts)分区,按(symbol, ts)排序,使同一合约的时间序列连续存储,提升范围查询效率。
CREATE TABLE market.tick (
ts DateTime64(3),
symbol LowCardinality(String),
price Decimal64(4),
volume UInt64,
bid Array(Decimal64(4)),
ask Array(Decimal64(4))
) ENGINE = MergeTree
PARTITION BY toYYYYMMDD(ts)
ORDER BY (symbol, ts)
TTL ts + INTERVAL 90 DAY;
四、安装部署与基本SQL操作
单机部署推荐使用官方APT/YUM仓库或Docker。以Ubuntu为例:
sudo apt-get install -y clickhouse-server clickhouse-client
sudo systemctl start clickhouse-server
clickhouse-client --query "SELECT version()"
分布式行情集群通常采用“分片+副本”拓扑:每个分片内配置2个副本,通过ReplicatedMergeTree实现副本同步,借助ZooKeeper或ClickHouse Keeper协调。配置片段示例:
<remote_servers>
<market_cluster>
<shard>
<replica><host>ch01</host><port>9000</port></replica>
<replica><host>ch02</host><port>9000</port></replica>
</shard>
<shard>
<replica><host>ch03</host><port>9000</port></replica>
<replica><host>ch04</host><port>9000</port></replica>
</shard>
</market_cluster>
</remote_servers>
基本SQL操作与标准SQL接近,但需注意ClickHouse的批量写入习惯:
-- 批量写入
INSERT INTO market.tick VALUES
('2025-01-02 09:30:00.123','IF2501',3850.2,120, [3849.8],[3850.6]);
-- 查询某合约某时段均价
SELECT symbol, avg(price) AS avg_price, sum(volume) AS total_vol
FROM market.tick
WHERE symbol='IF2501' AND ts BETWEEN '2025-01-02 09:30:00' AND '2025-01-02 10:00:00'
GROUP BY symbol;
五、复盘:从原理到落地的检查清单
- 确认查询是否只涉及少数列,若是则列式存储收益最大。
- 确认是否需要去重或预聚合,据此选择Replacing/Aggregating/Summing引擎。
- 价格用Decimal,时间用DateTime64,低基数列用LowCardinality。
- 分区键按天或小时,排序键以“合约+时间”为主。
- 写入必须攒批,避免小Part风暴;监控
system.parts与合并队列。 - 分布式部署优先ReplicatedMergeTree,副本数至少2,协调组件独立部署。