MarketMaker.cc Team
量化研究与策略
MarketMaker.cc Team
量化研究与策略
在算法交易中,盈利与亏损之间的差距往往以微秒计。数据传输架构是决定交易系统效率的关键因素之一。在本文中,我们将解析各个层级的通信技术:从与交易所的交互到内部微服务通信、存储和数据分发。

本文按层级组织——从“外部”(交易所通信协议)到“内部”(IPC、消息代理、存储),真实反映了算法交易平台的架构设计。
REST 是与交易所 API 交互最简单、最常见的方式。每个请求都是一个独立的 HTTP 连接:TCP 握手 → TLS 握手 → 发送请求 → 接收响应 → 关闭连接。
交易中的 REST 问题:
每个请求都会带来连接建立的开销。即使使用 HTTP keep-alive,“请求-响应”模型也意味着你接收数据的速度不可能快于发送请求的速度。这导致了轮询(polling)——即无限循环地询问“有新数据吗?”,这占用了交易所服务器高达 80% 的负载(据加密交易所开发人员估计)。交易所通常会引入频率限制(通常每分钟 10–1200 个请求),这使得 REST 不适用于高频策略。
此外,REST 是同步模型。发送订单时,你需要等待交易所响应而阻塞资源。如果交易所响应慢,整个系统都会变慢。
适用场景: 获取历史数据(K线, OHLCV)、账户管理(余额, 仓位)、非实时操作(DCA 机器人、每小时调仓)。
WebSocket 建立一个持久的 TCP 连接,数据可以双向流动。它以带有 Upgrade 头的普通 HTTP 请求开始,然后切换到双向二进制协议。
交易优势:
最大的优势是无请求开销。连接一旦建立,服务器即可即时推送数据。通过 WebSocket 传输的行情数据延迟通常小于 50 毫秒(从交易所网关到客户端)。你可以在一个连接上同时订阅 50 多个交易对。
关键点:通过 WebSocket 下单。 许多交易者不知道某些交易所(如 Binance, HitBTC, Deribit, Bybit 等)允许通过 WebSocket 发送订单,而不仅仅是接收数据。这比 REST 根本上更快,因为:
根据 Deribit 的数据,WebSocket 和 FIX 的执行速度多数情况下相当。REST 由于连接层的预处理而略慢。WebSocket 订单进入撮合引擎队列的方式与 FIX 订单相同。
混合上下文问题: 如果你通过 REST 发送订单,但通过 WebSocket 接收成交通知,会产生竞争条件(race condition):WebSocket 通知可能在 REST 请求完成之前到达。这会导致状态不一致。解决方案是完全转向异步模型,通过同一个 WebSocket 发送订单。
混合方法(最佳实践): WebSocket 用于行情数据 + WebSocket 用于订单(如果支持),REST 用于低频操作(历史数据、账户设置)。
FIX 是电子交易的行业标准,自 1992 年起(由 Fidelity Investments 和 Salomon Brothers 创建)一直存在。它是一种构建在 TCP 之上的二进制协议,专为交易操作设计。
FIX 架构:
FIX 消息由“标签=值 (tag=value)”对组成,由 SOH 字符分隔。例如,以 150 美元买入 100 股 AAPL 的订单如下:
8=FIX.4.2|35=D|49=BUYER|56=SELLER|11=ORD1001|38=100|40=2|54=1|55=AAPL|44=150.00
为什么 FIX 比 WebSocket 快: FIX 是原生 TCP 协议,没有 HTTP 层。AWS 在其针对加密交易所的 tick-to-trade 优化指南中,明确建议优先使用 FIX 而非 REST 和 WebSocket,以最小化协议引起的延迟。FIX 在微秒级别运行,而 WebSocket 通常在毫秒级别。
FIX 的主导领域: 直接市场准入 (DMA) 连接撮合引擎、机构领域的高频交易 (HFT)、流动性聚合(主经纪商通过 FIX 连接数十家银行)。
FIX 的局限性: 集成复杂、消息格式陈旧(文本形式的标签值不如二进制格式高效)、准入门槛高。在加密行业中,支持 FIX 的交易所数量有限。
SBE 是由 FIX 交易社区内的高性能工作组创建的二进制序列化格式。其目标是用紧凑的二进制表示取代文本格式的 FIX,以实现超低延迟交易。
SBE 的核心原则:
SBE + Aeron 是高性能交易系统的标准组合。Aeron 是来自 Real Logic 的开源消息系统(由原 LMAX CTO Martin Thompson 和原 29West CTO Todd Montgomery 创建)。它实际上是专为金融系统设计的传输层,运行在 UDP 和共享内存之上,延迟仅为几微秒。SBE 负责序列化,Aeron 负责传输。详见第 3.1 节。

| 参数 | REST | WebSocket | FIX | FIX+SBE |
|---|---|---|---|---|
| 延迟 | 10–100+ ms | 1–50 ms | 10–500 μs | 1–100 μs |
| 模型 | 请求-响应 | 双向推送 | 双向会话 | 双向会话 |
| 订单 | 是 (同步) | 是 (异步, 部分) | 是 (原生) | 是 (原生) |
| 连接预热 | 每次请求 | 一次性 | 一次性 | 一次性 |
| 格式 | JSON/文本 | JSON/二进制 | 标签值文本 | 二进制 |
| 集成难度 | 低 | 中 | 高 | 极高 |
行情数据从交易所进入系统后,开始内部处理:解析行情 → 策略计算 → 做出决策 → 发送订单。每个步骤都涉及服务间通信。
gRPC 是 Google 开发的基于 HTTP/2 的框架,使用 Protocol Buffers 进行序列化。对于算交,双向流(bidirectional streaming)尤为重要——客户端和服务器通过一个连接同时发送消息流。
为什么 gRPC 适合交易系统:
根据 SmartDev 的数据,70% 部署 AI HFT 的金融机构使用 gRPC 或原生 TCP 来实现微秒级响应。
架构示例: 行情收集器 (Rust) → gRPC 流 → 策略引擎 (Python/Rust) → gRPC 调用 → 订单路由 (Rust) → WebSocket/FIX → 交易所。
如果服务运行在同一台机器上(托管机房的典型场景),TCP 是多余的开销。Unix 域套接字 (UDS) 移除整个网络栈:无 TCP 握手、无路由、无校验。
基准测试显示显著差异:
根据 F. Werner (MPI Heidelberg) 的测量,gRPC UDS 比原生 UDS I/O 增加了约 10 倍开销(~130 μs 对比 ~13 μs)。这是为了抽象方便(HTTP/2 帧、protobuf 序列化)付出的代价。
何时使用 gRPC+UDS: 同一服务器上的进程间通信,且开发便利性(Schema, 代码生成)比极致延迟更重要时。UDS 还具有安全性优势——Unix 文件权限可控制访问。
何时不使用: 如果需要延迟 <10 μs,建议使用共享内存或不带 gRPC 的原生 UDS。具体数值:原生 UDS 中位延迟 ~13 μs,gRPC UDS ~130 μs。共享内存 (Aeron IPC) 小于 1 μs,LMAX Disruptor 环形缓冲区约为 50–100 纳秒。也就是说 gRPC+UDS 比原生 UDS 慢 10 倍,比共享内存慢 100–1000 倍。但延迟每降低一个台阶,代码复杂度就会上升一个台阶。
对于同主机的超低延迟,使用共享内存。两个进程映射同一块 RAM 区域,数据传递无需系统调用(初始设置除外)。
LMAX Disruptor 模式(共享内存中的环形缓冲区)可在单线程上每秒处理约 600 万个事件。这种方法是 LMAX 交易所及许多 HFT 系统的核心。
实现: Aeron IPC (Java/C++), Chronicle Queue (Java), 自定义 mmap 方案 (Rust/C++)。IronSBE (Rust 实现) 支持延迟约为 20 纳秒的共享内存 IPC。
Aeron 是由 Real Logic 开发的开源高性能消息传输系统。创建者是 Martin Thompson(原 LMAX CTO)和 Todd Montgomery(原 29West CTO)。它诞生于 2014 年,最初由一家美国主要交易所委托开发。
实践中的 Aeron: 它不是像 Kafka 那样的代理(Broker),也不是像 ZeroMQ 那样的套接字库。Aeron 是专为可预测低延迟设计的传输层。它运行在 UDP(网络)和共享内存(IPC)之上,同时提供可靠交付、定序和流量控制——这些是原生 UDP 所不具备的。你可以将 Aeron 视为“具有 UDP 延迟的 TCP”。
Aeron 特性:
Aeron Cluster — 用于容错状态机复制的扩展(Raft 共识),为交易系统提供一致性复制。
Aeron Archive — 以全速将消息持久化到磁盘,支持回放(Replay)。
与 Kafka 对比: 两者都使用分布式日志,但 Aeron 优化延迟(微秒级),而 Kafka 优化耐久性和吞吐量(毫秒级)。Aeron 用于实时交易逻辑,Kafka 用于数据管道和分析。
Kafka 是大规模事件流的事实标准。不适合交易决策的热路径(毫秒级延迟),但对于以下场景不可或缺:
在合理配置下,Kafka 端到端延迟约为 2–15 毫秒。对于 HFT 不可接受,但对于决策周期 >1 秒的策略足够。
Redis 是内存数据库,也可作为轻量级消息代理。
Redis Pub/Sub — 阅后即焚,亚毫秒级延迟。非常适合实时通知:价格更新、策略信号、告警。
Redis Streams — 增加了持久化和消费者组(类似小型 Kafka)。可以读取历史数据并确认处理 (ACK)。
NATS 是 Go 编写的极轻量消息系统。亚微秒延迟。NATS JetStream 扩展支持持久化和“仅一次交付 (exactly-once delivery)”。
提供套接字抽象的无代理库,用于点对点通信。ZeroMQ 吞吐量可达 500 万+消息/秒,历史悠久。nanomsg (及 NNG) 是其继承者,在小消息 (<64KB) 上延迟更佳。
Centrifugo 是 Go 编写的自托管发布/订阅服务器,优化了广播场景:一条消息 → 数万/百万客户端。支持 WebSocket, SSE, gRPC 等。
为何算交使用 Centrifugo:
QuestDB 是开源时序数据库,由 Java (Zero-GC), C++ 和 Rust 编写。
通常作为中间层:
极简主义的 C 语言向量数据库(二进制文件 <1MB),零依赖,SIMD 加速。专注于负载下的确定性延迟,这在高频交易中至关重要。
| 格式 | 编解码速度 | 体积 | 零拷贝 | 适用场景 |
|---|---|---|---|---|
| JSON | 慢 | 大 | 否 | REST API, 调试, 日志 |
| Protobuf | 快 | 紧凑 | 否 | gRPC, 微服务通信 |
| SBE | 极快 | 极小 | 是 | HFT, 撮合引擎 |
| FlatBuffers | 非常快 | 紧凑 | 是 | 游戏开发, 中等延迟 |
SBE 通过固定字段位置实现了极速性能。对于交易消息(订单、成交报告)非常合适。
交易所 → Collector (Rust) → Redis (热缓存) → 策略引擎 (Python) → gRPC (UDS) → 订单路由 (Rust) → 交易所。
交易所 Feed → 网卡 (内核旁路) → Aeron IPC (共享内存) → 策略 (C++, 单线程) → SBE 编码 → Aeron → FIX → 交易所。
不要过度优化非瓶颈。 如果你的策略决策需要 50 毫秒,那么为了节省 100 微秒而将 gRPC 换成 Aeron 是没有意义的。混合架构是常态:REST 用于配置,gRPC 用于核心通信,WS 用于行情下发。
不存在完美的通用通信技术。系统每个层级都有其需求:外部(兼容性)、内部热路径(极低延迟)、数据管道(可靠性)、客户端(灵活性)。有效架构的关键是理解每个组件的要求,并为特定任务选择合适的工具。