第二章:延迟的构成——网络、内核、应用层与硬件
做市系统的延迟,说白了就是数据包从交易所到策略引擎,再回到交易所的完整路径上,每一站消耗的时间总和。
我刚开始做低延迟交易系统时,总觉得延迟是个黑盒。后来我亲手搭了一套全链路监控,才真正看清——延迟不是单一问题,而是多个环节的叠加。你想想看,一个订单从发出到成交确认,中间要经过多少道关卡?
我个人习惯把延迟拆成四层:网络延迟、内核延迟、应用层延迟、硬件延迟。每一层都有它的坑,也有它的优化空间。
2.1 全景图:数据包的完整旅程
先看一张全景图。这张图我画了很多遍,每次给团队培训都会拿出来讲。
这张图我每次看都有新体会。数据包从交易所出发,经过网络、网卡、内核协议栈,最后到达策略引擎。策略算完,订单再原路返回。每一站都有延迟,每一站都能优化。
2.2 网络延迟:物理距离的硬约束
网络延迟是最「老实」的延迟。光速是物理极限,谁也没法突破。
我记得有一次,团队把服务器从纽约搬到新泽西,就为了离交易所的机房更近。搬完之后,延迟从 1.2ms 降到了 400μs。效果立竿见影。
网络延迟主要来自三方面:
- 传播延迟:光在光纤中传播的速度大约是 2/3 光速。每 100 公里大约 500μs。
- 传输延迟:数据包大小除以带宽。万兆网卡下,64 字节的小包大约 51ns。
- 处理延迟:交换机、路由器处理数据包的时间。好的交换机可以做到 1-5μs。
关键认知:网络延迟中,传播延迟是硬约束,你只能通过「搬得更近」来解决。传输延迟和处理延迟可以通过硬件升级来优化。
2.3 内核延迟:协议栈的沉重包袱
内核延迟,说白了就是操作系统帮你处理网络数据时花的时间。
标准 Linux 内核处理一个网络数据包,要走完整的协议栈路径:中断处理、软中断、协议解析、socket 缓冲区、上下文切换……这一套下来,10-50μs 就没了。
我刚开始做优化时,觉得内核挺快的。直到我用 perf 工具一测,才发现内核协议栈占了整个延迟的 40% 以上。嗯,这里要注意——内核延迟往往是最大的优化空间。
内核延迟的典型构成:
| 环节 | 典型延迟 | 说明 |
|---|---|---|
| 中断处理 | 2-5μs | 网卡触发中断,CPU 保存上下文 |
| 协议栈处理 | 5-20μs | TCP/IP 协议解析、校验和计算 |
| socket 缓冲区 | 1-5μs | 数据从内核态拷贝到用户态 |
| 上下文切换 | 2-10μs | 内核态到用户态的切换 |
优化思路:使用 DPDK、Solarflare 的 OpenOnload 等技术,可以绕过内核协议栈,让应用直接操作网卡。我曾经在一个项目中用 DPDK 把内核延迟从 30μs 降到了 2μs。
2.4 应用层延迟:代码质量决定一切
应用层延迟,说白了就是你的策略代码跑得有多快。
这一层最容易被忽视。很多人觉得「我的策略逻辑很复杂,慢一点正常」。但你想过没有——同样的策略,用 C++ 写和用 Python 写,延迟能差 10 倍以上。
应用层延迟的常见来源:
- 内存分配:频繁的 malloc/free 会导致延迟抖动。我建议用对象池或预分配。
- 锁竞争:多线程环境下,锁的争抢会让延迟飙升。用无锁数据结构或者读写锁分离。
- 日志打印:每条订单都打日志?小心 I/O 成为瓶颈。异步日志是标配。
- 垃圾回收:Java/C# 的 GC 暂停是噩梦。做市系统我建议用 C++ 或 Rust。
避坑指南:我曾经在一个项目中,发现策略引擎的延迟每隔几分钟就会突然跳到 100ms 以上。排查了两天,最后发现是日志库在缓冲区满时做了同步写入。换成异步日志后,问题消失。
2.5 硬件延迟:选对设备省一半功夫
硬件延迟,包括网卡、CPU 缓存、内存访问、PCIe 总线等各个环节的延迟。
我个人习惯把硬件延迟分成两类:
- 确定性延迟:比如内存访问延迟,大约 100ns。这个相对固定。
- 非确定性延迟:比如 CPU 缓存未命中,延迟可能从 1ns 跳到 100ns。这个最坑人。
硬件延迟的典型数据:
| 硬件环节 | 典型延迟 | 优化方向 |
|---|---|---|
| L1 缓存命中 | 1ns | 数据局部性优化 |
| L2 缓存命中 | 4ns | 减少数据规模 |
| 主存访问 | 100ns | 减少随机访问 |
| PCIe 传输 | 1-5μs | 使用 NUMA 绑定 |
| 网卡硬件处理 | 1-5μs | 使用 FPGA 或智能网卡 |
核心原则:硬件延迟的优化,本质上是让数据尽量靠近 CPU。把热数据放在 L1 缓存里,把网卡和 CPU 绑定在同一个 NUMA 节点上——这些细节做好了,延迟能降一个数量级。
2.6 延迟的叠加效应
你想想看,每一层都优化一点,叠加起来效果就很可观。
举个例子:
- 网络延迟:从 100μs 优化到 50μs(搬机房)
- 内核延迟:从 30μs 优化到 3μs(DPDK)
- 应用层延迟:从 20μs 优化到 5μs(代码优化)
- 硬件延迟:从 10μs 优化到 3μs(NUMA 绑定 + 缓存优化)
总延迟从 160μs 降到了 61μs。这就是做市系统从毫秒到微秒的进化路径。
我个人习惯在做优化时,先做全链路延迟测量,找到最大的瓶颈,然后集中火力解决它。不要一上来就想着「全都要优化」,那样反而容易顾此失彼。
公众号:蓝海资料掘金营,微信deep3321