第一章:CPU信息查看——知己知彼,百战不殆

做CPU亲和性绑定,第一步是什么?

不是写代码,不是配参数。而是——搞清楚你的CPU到底长什么样。

我见过太多人,上来就绑核,结果绑到了超线程的兄弟核上,性能反而下降。嗯,这种坑我踩过不止一次。所以今天咱们先花点时间,把CPU的家底摸清楚。

1.1 lscpu——三秒摸清CPU家底

我个人习惯,登录一台新机器,第一件事就是敲lscpu。这命令就像CPU的身份证,信息全、格式清。

$ lscpu

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                32
On-line CPU(s) list:   0-31
Thread(s) per core:    2
Core(s) per socket:    8
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 85
Model name:            Intel(R) Xeon(R) Gold 6248R CPU @ 3.00GHz
Stepping:              7
CPU MHz:               3000.000
CPU max MHz:           4000.0000
CPU min MHz:           1200.0000
BogoMIPS:              6000.00
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              1024K
L3 cache:              36608K
NUMA node0 CPU(s):     0-7,16-23
NUMA node1 CPU(s):     8-15,24-31

这里有几个关键字段,做量化交易系统必须盯死:

字段 含义 为什么重要
CPU(s) 逻辑CPU总数 决定你能绑多少个线程
Thread(s) per core 每核心线程数 2就是开了超线程,小心假核
Core(s) per socket 每颗CPU的物理核心数 真正的并行计算单元
Socket(s) 物理CPU颗数 跨Socket访问内存延迟高
NUMA node(s) NUMA节点数 交易系统必须考虑NUMA
NUMA node0 CPU(s) 节点0包含的CPU列表 绑核时尽量绑在同一节点

核心结论:量化交易系统的收报线程、风控线程、交易线程,最好绑在同一个NUMA节点上。跨节点访问内存,延迟可能增加30%-50%。

1.2 /proc/cpuinfo——更细粒度的CPU档案

lscpu是概览,想看每个逻辑CPU的详细信息,就得翻/proc/cpuinfo

$ cat /proc/cpuinfo | head -30

processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 85
model name      : Intel(R) Xeon(R) Gold 6248R CPU @ 3.00GHz
stepping        : 7
microcode       : 0x500320a
cpu MHz         : 3000.000
cache size      : 36608 KB
physical id     : 0
siblings        : 16
core id         : 0
cpu cores       : 8
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 22
wp              : yes

这里我重点看三个字段:

  • processor:逻辑CPU编号,从0开始
  • physical id:属于哪颗物理CPU
  • core id:属于哪个物理核心

为什么要看这三个?

举个例子。假设你看到processor 0和processor 16的physical id都是0,core id都是0。这说明什么?它们其实是同一个物理核心上的两个超线程兄弟。你如果把两个计算密集型的线程绑到这两个核上,它们会抢同一个执行单元,性能反而下降。

我的经验:在交易系统中,收报线程和计算线程一定要绑到不同的物理核心上。我曾经在一个项目里,把两个高频线程绑到了同一个物理核心的两个超线程上,结果丢包率直接翻倍。排查了两天才发现是这个问题。

1.3 cpuinfo_cur_freq——实时频率监控

光看静态信息还不够。CPU频率是会动态变化的,尤其是现在的Intel和AMD处理器,都有睿频和节能机制。

实时频率怎么看?

$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
3000000

单位是kHz。3000000 kHz = 3.0 GHz。

但注意——这个文件不是所有内核版本都支持。如果找不到,可以试试:

$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
3000000

这两个文件有什么区别?

文件 含义 可用性
cpuinfo_cur_freq 硬件上报的当前频率 部分内核/驱动支持
scaling_cur_freq 调频策略决定的当前频率 几乎都支持

避坑指南:我曾经在某个云服务器上发现cpuinfo_cur_freq一直显示为0,以为是硬件坏了。后来才发现是虚拟化环境不支持这个接口。所以建议优先用scaling_cur_freq,兼容性更好。

为什么要监控实时频率?

做量化交易的朋友都知道,延迟就是金钱。如果你的CPU因为温度过高或者节能策略,从3.0GHz降到了2.0GHz,你的交易延迟可能从10微秒变成15微秒。在纳秒级竞争的市场里,这5微秒可能就是胜负手。

我建议在交易系统上线前,跑一个频率监控脚本:

#!/bin/bash
# 监控所有CPU核心的实时频率
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
    cpu_num=$(basename $cpu | grep -o '[0-9]\+')
    freq=$(cat $cpu/cpufreq/scaling_cur_freq 2>/dev/null)
    echo "CPU $cpu_num: $((freq / 1000)) MHz"
done

跑完之后,看看所有核心的频率是否一致。如果某个核心频率明显偏低,那可能就是散热问题或者硬件故障。

1.4 知识体系总览

说了这么多,咱们用一张图把CPU信息查看的知识体系串起来:

CPU信息查看知识体系 lscpu 命令 /proc/cpuinfo 频率监控 关键字段 • CPU(s): 逻辑CPU总数 • Thread(s) per core: 超线程 • NUMA node: 内存拓扑 • Socket(s): 物理CPU数 核心字段 • processor: 逻辑CPU编号 • physical id: 物理CPU归属 • core id: 物理核心归属 • cpu cores: 核心总数 监控接口 • cpuinfo_cur_freq • scaling_cur_freq • 频率一致性检查 • 降频预警 核心目标:为CPU亲和性绑定提供准确的硬件拓扑信息 避免跨NUMA、跨Socket、超线程冲突等性能陷阱 量化交易系统应用场景 收报线程绑核 → 确认NUMA节点 → 避免跨节点延迟 计算线程绑核 → 确认物理核心 → 避免超线程争抢

这张图把三个工具的关系理清了。lscpu看宏观,/proc/cpuinfo看微观,频率监控看动态。三者结合,你才能对CPU的拓扑和状态了如指掌。

一句话总结:绑核之前,先看拓扑。不看拓扑就绑核,就像闭着眼睛开车——迟早要出事。

好了,CPU信息查看就讲到这里。下一章咱们聊聊怎么把这些信息用到实际的绑核操作中。记住我今天说的——先摸清家底,再动手干活。


公众号:蓝海资料掘金营,微信deep3321