
本文字数:5552;估计阅读时间:14 分钟
作者:Lionel Palacin
本文在公众号【ClickHouseInc】首发

金融市场从不休眠。价格时时波动,交易以毫秒速度执行,行情每秒更新数千次。如何实时捕捉这些高频数据并将其转化为可用信息,是一项复杂的工程挑战。但如果拥有合适的技术栈,这一问题也能被优雅地解决。
StockHouse 是一个完整的演示项目,展示了如何通过 ClickHouse、Massive 和 Perspective 搭建一套实时流式市场分析应用。
你可以通过访问 https://stockhouse.clickhouse.com 在线体验该系统。

StockHouse 从 Massive 提供的 WebSocket API 实时接入市场行情数据,并将其高效写入 ClickHouse 数据库。同时,它通过网页仪表盘实现毫秒级数据可视化更新,完整演示了如何从数据采集、存储、聚合到实时展示,全流程处理高频、高吞吐量的市场数据。
为何要构建这样一个系统?
市场数据是检验实时分析系统能力的最佳场景:更新速度快、变动持续、数据规模大。而传统分析系统在面对每秒数百万次更新时,往往难以保持实时性和稳定性。
ClickHouse 则正好为此类场景而设计 —— 具备高性能写入、低延迟查询能力,同时对时间序列数据支持高效压缩。
StockHouse 将这些能力转化为实际产品原型,具体包括:
-
实时接入 Massive 提供的股票与加密货币数据流
-
使用针对时间序列优化的数据模型,实现高效插入与快速查询
-
借助 ClickHouse 的物化视图,进行低延迟的实时分析
-
构建交互式可视化界面,数据一更新即可自动呈现
该系统足够轻量,开发者可以本地运行调试;同时也具备可扩展性,能够支撑每秒处理数百万事件的高负载环境。无论你是构建交易仪表盘、实时分析工具,还是构建内部可观测系统,StockHouse 都是一个理想的起点。
架构总览:StockHouse 是如何构建的
StockHouse 由五个核心组件构成,形成了一个简洁高效的实时流处理架构:
1. 数据源:通过 Massive 的 WebSocket API 实时接入股票与加密货币市场数据流
2. 数据采集器(Ingester):使用 Go 实现的服务,高性能消费数据流并写入 ClickHouse
3. 数据库层:基于 ClickHouse 的表与物化视图,专为低延迟、高吞吐分析场景优化
4. 后端接口:一个用 Node.js 编写的 API 服务,负责高效桥接前端与数据库
5. 前端可视化:使用 Vue.js 与 Perspective 构建的仪表盘,实现毫秒级图表更新

下面我们来看看这个架构背后的一些关键技术设计。
Go 实现的高性能采集器
StockHouse 的数据采集器使用 Go 编写,以便在处理高频数据流时保持出色的性能和资源效率。Go 的并发机制(如 goroutine 和 channel)使其能够非阻塞地同时处理多个 WebSocket 数据源。
在数据写入方面,采集器采用 ClickHouse 的原生二进制列式协议,避免了文本格式解析开销,大幅提升了写入吞吐能力。ClickHouse 的输入格式性能基准测试也验证了这一方案的效率。Netflix 在自建采集平台时也采用了相同做法。
这种架构支持每秒推送数百万行数据到 ClickHouse,同时确保延迟可控、资源占用可预期。每条交易、报价或行情记录都会按批处理方式写入,在保证实时性的同时兼顾系统吞吐。
整体来看,这是一套既能处理高频市场流、又可持续运行的稳定数据采集管道。
Perspective:前端的实时可视化引擎
在前端,StockHouse 选用了开源图表引擎 Perspective,它最初由摩根大通(J.P. Morgan)开发,并通过 FINOS 基金会对外开源。该工具专为处理大规模、持续变化的金融数据而设计,非常适合我们的实时场景。
Perspective 的核心计算引擎基于 C++,并被编译为 WebAssembly,可将聚合、透视、过滤等计算任务放在主线程之外执行。即便系统每秒处理上万次数据更新,也能保持 UI 的流畅响应。
其一大技术优势是原生支持 Apache Arrow —— 一种高性能的内存列式数据交换格式。
ClickHouse 同样支持以 Arrow 作为输出格式,意味着查询结果可以直接以二进制流方式发送到浏览器,完全跳过 JSON 解析,数据无需拷贝即可交给 Perspective 渲染。这种“零开销直连”架构极大提升了端到端数据传输效率。
最终效果是:StockHouse 仪表盘可以实时拉取 ClickHouse 数据,快速传入 Perspective 并立即渲染图表,在保持极低延迟和资源消耗的同时,确保可视化界面始终与市场数据保持同步,带来真正的“毫秒级响应”体验。
Node.js 的连接池优化:关键但轻量的中间层
在前端与 ClickHouse 数据库之间,我们设计了一个轻量级的 Node.js 后端。虽然体积小,但它在性能表现上起到了关键作用。
该服务通过维护一个持久的连接池,避免了每次查询都重新建立数据库连接所带来的资源开销。这种方式不仅节省了连接时间,还能复用查询上下文,确保请求执行时具备最低延迟。
对于像实时仪表盘这类高频、连续查询的场景而言,这样的优化非常关键 —— 即使每次查询只快上几毫秒,也可能是用户感受到“流畅”与“卡顿”的分界线。
利用物化视图进行预聚合处理
虽然 ClickHouse 在处理原始数据聚合时已经相当高效,但在实时分析中,每一毫秒的响应延迟都影响用户体验。
为进一步提升查询速度,StockHouse 在数据写入阶段就使用物化视图(Materialized View)完成预聚合操作。

举例来说,系统中用于展示加密货币行情的表,会持续更新每个交易对的每日价格信息。
如果每次查询都现算聚合数据,会增加不必要的延迟。而通过物化视图,我们可以在数据写入时自动完成这些聚合逻辑。
-- Create table to store daily crypto price information
CREATE TABLE agg_crypto_trades_daily
(
`event_date` Date,
`pair` LowCardinality(String),
`open_price_state` AggregateFunction(argMin, Float64, UInt64),
`last_price_state` AggregateFunction(argMax, Float64, UInt64),
`volume_state` AggregateFunction(sum, Float64),
`latest_t_state` AggregateFunction(max, UInt64)
)
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, pair);
-- MV to keep daily price information up to date
CREATE MATERIALIZED VIEW mv_crypto_trades_daily TO agg_crypto_trades_daily
(
`event_date` Date,
`pair` String,
`open_price_state` AggregateFunction(argMin, Float64, UInt64),
`last_price_state` AggregateFunction(argMax, Float64, UInt64),
`volume_state` AggregateFunction(sum, Float64),
`latest_t_state` AggregateFunction(max, UInt64)
)
AS SELECT
toDate(fromUnixTimestamp64Milli(t, 'UTC')) AS event_date,
pair,
argMinState(p, t) AS open_price_state,
argMaxState(p, t) AS last_price_state,
sumState(s) AS volume_state,
maxState(t) AS latest_t_state
FROM crypto_trades
GROUP BY
event_date,
pair;
这样一来,实际用于前端查询的 SQL 语句就可以非常简单,通常几毫秒内即可返回结果,显著提升页面的实时性与交互性。
WITH toDate(now('UTC')) AS curr_day
SELECT
t.pair AS pair,
argMaxMerge(t.last_price_state) AS last,
argMinMerge(t.open_price_state) AS open,
argMaxMerge(q.bid_state) AS bid,
argMaxMerge(q.ask_state) AS ask,
round(((last - open) / open) * 100, 2) AS change,
sumMerge(t.volume_state) AS volume,
toUnixTimestamp64Milli(now64()) -
greatest(maxMerge(t.latest_t_state), maxMerge(q.latest_t_state)) AS last_update
FROM stockhouse.agg_crypto_trades_daily AS t
LEFT JOIN stockhouse.agg_crypto_quotes_daily AS q
USING (event_date, pair)
WHERE event_date = curr_day
AND pair in ('BTC-USD','ETH-USD','XRP-USD','ZEC-USD','ALEO-USD','SOL-USD','DASH-USD','SUI-USD','ICP-USD','NEAR-USD','TAO-USD','DOGE-USD','HBAR-USD','LINK-USD','ZK-USD','LTC-USD','XLM-USD','ADA-USD','ZEN-USD','ALCX-USD','APT-USD','USDT-USD','SEI-USD','SYRUP-USD','ONDO-USD','AERO-USD','DOT-USD','USDC-USD','XTZ-USD','MINA-USD','FIL-USD','AAVE-USD')
GROUP BY pair
ORDER BY pair ASC
这种“原始数据 → 实时聚合 → 可视化”的架构模式,是在 ClickHouse 中平衡数据灵活性与响应速度的标准实践。原始明细数据仍然保留,便于做历史回溯或复杂分析,而预聚合表则确保前端界面始终保持实时、流畅。
架构全景:五步打造毫秒级实时分析平台
整个系统的工作流程如下:
1. 数据接入:Massive 通过 WebSocket 持续推送实时市场数据
2. 数据采集:Go 编写的采集服务解析流数据并通过原生接口高效写入 ClickHouse
3. 实时聚合:物化视图在写入阶段完成预聚合处理,提升查询响应速度
4. 中间服务:Node.js 后端通过连接池高效转发查询请求
5. 前端展示:基于 Vue 和 Perspective 构建的仪表盘实现毫秒级数据可视化刷新
最终呈现的,是一个始终与市场行情保持同步的流畅、响应迅速的实时仪表盘。
上手体验:亲自部署你的 StockHouse
你可以直接访问在线演示:[stockhouse.clickhouse.com],也可以参考 GitHub 仓库提供的安装说明在本地快速部署属于你自己的版本。
即可将实时行情流入你自己的 ClickHouse 实例中开始分析。Massive 提供免费的基础接入额度,付费版本支持无限制 API 调用及完整数据访问,非常适合从原型验证到正式部署的全流程需求。
此外,如果你更倾向于使用 SQL 直接探索数据,StockHouse 的原始数据也已开放至 https://play.clickhouse.com,欢迎试用。
结语:从演示到参考架构
StockHouse 不只是一个演示系统,更是一套可复制的参考架构,适用于任何构建实时分析系统的开发者与团队。
它展示了如何将三种核心能力组合在一起:实时数据流处理(由 Massive 提供);高性能分析引擎(ClickHouse 提供极速写入与查询);高效可视化层(Perspective 带来毫秒级图表刷新体验)。
无论你正在追踪金融市场、分析物联网传感器数据,还是构建基础设施监控平台,核心理念都是一致的:快速采集、结构化存储、极速响应,只要架构合理,实时系统也可以既灵活又高效。
征稿启示
面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

243

被折叠的 条评论
为什么被折叠?



