2. 测试环境搭建:硬件选型与系统调优
做性能基准测试,最怕什么?
怕你测出来的数据,根本不是你系统的真实水平。
硬件没选对,操作系统没调优,时间不同步——这三件事但凡有一件没做好,你的测试结果就是一堆废纸。我见过太多团队,花了几十万买机器,跑出来的延迟数据却比隔壁用旧服务器还差。为什么?因为环境没搭对。
这一章,我们就来聊聊怎么把测试环境搭扎实。从硬件选型到内核调优,再到时间同步,每一步我都会把我在项目中踩过的坑、总结的经验讲清楚。
2.1 硬件选型:别让硬件拖了后腿
量化交易系统对硬件的要求,说白了就三个字:快、稳、准。
快,是延迟要低;稳,是不能掉链子;准,是时间要精确。我们一个一个来看。
2.1.1 CPU:核心频率比核心数量更重要
很多人选CPU,第一反应是看核心数。16核、32核,听着就厉害。但做交易系统,尤其是高频交易,单核性能才是王道。
为什么?因为交易系统的核心逻辑,往往是单线程的。你想想看,行情数据来了,你得按顺序处理,不能并行。多核的优势主要体现在并发处理多个策略或回测任务上。
我个人习惯,选CPU时优先看这几个指标:
- 主频:越高越好,建议4.0GHz以上。我见过有人用3.0GHz的CPU跑高频策略,结果行情波动一大,处理不过来,直接丢包。
- 睿频:单核睿频能力要强。有些CPU全核跑不高,但单核能冲到5.0GHz以上,这种就很适合。
- 缓存:L3缓存越大越好。缓存命中率高,能减少内存访问延迟。
- NUMA架构:多路服务器要注意NUMA节点。跨节点访问内存,延迟会高不少。
2.1.2 内存:容量够用就行,频率和时序是关键
内存这块,很多人容易走极端。要么买超大容量,要么买最便宜的。
其实,对于交易系统来说,内存的频率和时序比容量更重要。为什么?因为行情数据要频繁读写,内存延迟直接影响处理速度。
我建议的配置:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 容量 | 64GB - 128GB | 够用就行,太多也用不上 |
| 频率 | DDR4-3200 或更高 | 频率越高,带宽越大 |
| 时序 | CL14 或更低 | 时序越低,延迟越小 |
| 通道 | 双通道或四通道 | 通道越多,带宽越高 |
2.1.3 网卡:别用板载网卡做交易
这一点,我怎么说都不为过。板载网卡是给办公用的,不是给交易用的。
板载网卡的问题在于:
- CPU占用高:数据包处理全靠CPU,拖累主业务
- 延迟不稳定:受系统中断影响大,延迟抖动明显
- 功能有限:不支持硬件时间戳、RSS等高级功能
我建议用Solarflare或Mellanox的网卡。这些网卡支持:
- 硬件时间戳:精确到纳秒级,对时间同步至关重要
- RSS(接收端缩放):多队列并行处理,降低CPU负载
- DPDK:用户态驱动,绕过内核协议栈,延迟极低
2.2 操作系统调优:把系统的潜力榨出来
硬件选好了,操作系统也得调。默认配置是给通用场景用的,不是给低延迟交易用的。
2.2.1 内核参数调优
Linux内核有很多参数可以调。我挑几个最关键的:
# 网络相关
net.core.rmem_max = 134217728 # 接收缓冲区最大大小
net.core.wmem_max = 134217728 # 发送缓冲区最大大小
net.core.netdev_budget = 600 # 每次轮询处理的数据包数量
net.core.netdev_budget_usecs = 1000 # 轮询时间上限(微秒)
# 中断相关
kernel.sched_migration_cost_ns = 5000000 # 进程迁移成本
kernel.sched_autogroup_enabled = 0 # 关闭自动分组
# 内存相关
vm.swappiness = 10 # 尽量少用swap
vm.dirty_ratio = 5 # 脏页比例上限
vm.dirty_background_ratio = 2 # 后台脏页比例
这些参数怎么来的?不是拍脑袋想的。我一般会先用sysctl -a看当前值,然后根据业务场景逐步调整。每次改完,跑一遍基准测试,看延迟和吞吐量的变化。
2.2.2 中断绑定:把网卡中断固定到特定CPU核心
默认情况下,网卡中断会在所有CPU核心之间轮转。这会导致一个问题:CPU缓存频繁失效,延迟不稳定。
解决办法是中断绑定。把网卡中断固定到某个或某几个CPU核心上,其他核心专心处理业务逻辑。
具体做法:
- 查看网卡中断号:
cat /proc/interrupts | grep eth0 - 查看CPU核心编号:
lscpu - 绑定中断到指定核心:
echo "2" > /proc/irq/123/smp_affinity(2表示CPU核心1)
嗯,这里要注意:smp_affinity的值是十六进制掩码。比如你想绑定到CPU核心0和核心2,掩码就是0x5(二进制0101)。
2.2.3 其他调优技巧
- 关闭CPU节能:在BIOS中关闭C-States和P-States,避免CPU频率波动。
- 关闭超线程:超线程虽然能提高吞吐量,但会引入延迟不确定性。做低延迟交易,建议关闭。
- 使用isolcpus:在内核启动参数中隔离特定CPU核心,不让系统调度普通进程到这些核心上。
# 在GRUB配置中添加
isolcpus=2,3,4,5,6,7 nohz_full=2,3,4,5,6,7 rcu_nocbs=2,3,4,5,6,7
2.3 时间同步:差一毫秒,可能亏一套房
时间同步,是量化交易系统里最容易忽视、但后果最严重的问题。
你想想看,如果你的系统时间比交易所慢了1毫秒,你看到的行情就是过时的。你下的单,可能比别人晚了一辈子。
2.3.1 NTP vs PTP:怎么选?
| 特性 | NTP | PTP |
|---|---|---|
| 精度 | 毫秒级(1-10ms) | 微秒级(<1μs) |
| 硬件要求 | 低,普通网卡即可 | 高,需要支持PTP的网卡和交换机 |
| 适用场景 | 回测、中低频交易 | 高频交易、行情数据对齐 |
| 配置复杂度 | 简单 | 中等 |
我的建议是:能做PTP就做PTP,做不了再用NTP。
为什么?因为NTP的精度受网络延迟影响太大。你测出来是1ms的误差,实际可能到10ms。而PTP利用硬件时间戳,精度可以到100纳秒以内。
2.3.2 PTP配置实战
以Linux系统为例,使用ptp4l和phc2sys:
# 安装工具
apt-get install linuxptp
# 配置ptp4l(/etc/linuxptp/ptp4l.conf)
[global]
network_transport L2
delay_mechanism P2P
time_stamping hardware
tx_timestamp_timeout 10
logSyncInterval 0
logAnnounceInterval 1
logMinDelayReqInterval 0
# 启动PTP从时钟
ptp4l -f /etc/linuxptp/ptp4l.conf -i eth0 -m
# 同步系统时钟到PTP硬件时钟
phc2sys -s eth0 -c CLOCK_REALTIME -m -O 0
2.3.3 验证时间同步精度
配置完了,怎么知道准不准?
用pmc工具查看:
# 查看PTP状态
pmc -u -b 0 'GET CURRENT_DATA_SET'
pmc -u -b 0 'GET TIME_STATUS_NP'
或者用chronyc(如果用的是NTP):
chronyc tracking
chronyc sources -v
我一般会连续监控24小时,看时间偏差的均值和标准差。如果偏差超过10微秒,就得排查问题了。
2.4 本章小结
测试环境搭建,说白了就是三件事:
- 硬件:选对CPU、内存、网卡,别让硬件成为瓶颈
- 系统:调优内核参数、绑定中断、隔离核心,把系统潜力榨出来
- 时间:用PTP做高精度时间同步,确保数据对齐
这三件事做好了,你的基准测试结果才有参考价值。否则,你测出来的不是系统的性能,而是环境的混乱程度。
下一章,我们会聊测试工具的选择和基准测试脚本的编写。到时候,我会分享一些我自己写的测试脚本,以及怎么避免常见的测试陷阱。