资源合池化后的异构差异问题解析--CPU分层现象和解决思路

0 阅读21分钟

1. 背景

自1965年戈登·摩尔提出摩尔定律以来,半导体行业持续推动芯片技术的革新,IDC(互联网数据中心)为平衡成本效益和多样化需求,逐渐形成了包含Intel、AMD、ARM等多种架构的混合部署模式。早期IDC往往通过小集群分别管理,这种方式虽然简单,但随着硬件代际和架构的增多,资源隔离问题日益凸显,不同集群间的计算资源无法共享,导致资源利用困难、运营成本上升。

为解决这一问题,业界开始采用资源合池技术。该技术通过虚拟化、容器化和智能调度系统,将不同架构、不同代次的硬件资源抽象成统一的资源池,打破物理集群的界限,实现计算、存储和网络资源的全局共享。这种方式不仅提高了资源利用率,还降低了管理复杂度,使IDC能够更灵活地应对动态负载,支持弹性扩展,最大化数据中心的整体计算能力。

图片

图1 资源合池示意图

尽管资源合池化局有上述的许多优点,但是异构系统的统一调度增加了技术复杂度,其矛盾主要来自于硬件的设计差异,进而影响到了系统层面的表现差异,其中最为明显的是,应用在不同硬件上的运行效率差异会给容量规划带来困难,例如同一实例面对相同的负载压力在不同的硬件上运行的CPU需求量存在区别,具体会呈现为CPU使用率的分层现象。此时业务很难根据CPU算力需求进行容量规划,若是依据高位线进行负载规划,在低位线的机器上会存在资源浪费。如果按照低位线尽心负载规划,则会由于硬件能力的不足导致业务的SLA无法被满足。因此明确并尽可能的消弭不同硬件的所导致的应用表现差异至关重要。本文会以CPU分层现象为视角切入来排查和解决此类问题。

2. 排查方法论

根据上文所述,CPU分层现象的具体表现,如图2所示:

图片

图2 业务机器CPU利用率图

同一业务在监控面板上呈现出多个层次的CPU利用率,业务从监控上难以判断容量是否打满,带来稳定性的风险。

造成CPU分层现象的原因可以分为以下两个方面:

  1. 硬件差异:如CPU、内存、磁盘和网络等。
  2. 软件差异:如驱动 软件库 编译链等。

缓解分层显现的核心是针对分层较为严重的极端案例,寻找部分机器运行较差的核心原因,通过各种方法缓解瓶颈,提升系统总体资源利用率,具体如流程图3所示。

图片

图3 缓解CPU分层流程图

解决这类问题首先是对业务申请的资源,根据硬件情况进行修正。由于不同硬件存在基础算力差异,相同负载的业务呈现的CPU利用率本身就会存在区别,这种符合预期的区别,不是我们需要解决的问题。为了排除这个干扰,进行合理的修正,需要通过benchmark测试得到机器的基础算力差异,具体如下表1:

机型算力标准值
Xeon Silver 4110*2320
Xeon E5-2630 v4*2448 
…………
AMD EPYC 7502P*1883
AMD EPYC 7402P*1797 

表1 CPU benchmark测试

然后利用资源调度平台,根据测试接结果修正资源分配量,消除差异。

基础算力差异修正之后,仍旧存在严重分层现象的,就是我们需要分析的目标场景。位于监控上下边界的个例,就是该场景极端对照组。

每个场景的切入点和分析方法各不相同,限于篇幅限制,我们列举了NUMA、cache和降频三个典型问题场景来展开介绍。

3. NUMA问题场景

3.1. 问题描述

NUMA造成的CPU分层现象大多集中在内存密集型业务,主要原因是CPU访问不同NUMA节点内存的速度差异,在系统中表征为Node Distance。以Intel(R) Xeon(R) CPU E5-2630 v4为例。双numa不同节点之间的距离如下表1:

图片

表1 Intel Node Distance表

这里同节点的访问距离为10个单位,跨节点为21个点位,是一种比较平衡的布局,在真实生产环境中,当节点数量较多时,不同架构可能还会出现不平衡的布局。如Intel(R) Xeon(R) Platinum 8468V存在四个节点。Node Distance如下表2:

图片

这种情况下的NUMA差异影响会更为复杂。

当业务代码具有良好的空间局部性(即某段时间内访问的内存都集中在同一个NUMA节点内)时,访存性能会显著受到数据位置的影响。

典型场景是在相同机型、软硬件和任务负载下,两台机器也会跑出不一致的CPU利用率曲线。其原因在于CPU的跨NUMA访问,假设在某台机器进程原本在CPU0(属于NUMA node 0)上运行,其代码和数据都被优先分配在node 0的内存节点上。当进程经过调度后被迁移到CPU1(属于NUMA node 1)运行时,由于所需内存仍位于node 0,此时每次内存访问都需要跨节点操作,导致访存延迟从10增加到21,造成明显的性能劣化。这种由于NUMA访问延迟不均而引发的差异,正是 CPU 分层现象的典型原因之一。

3.2. 指标反馈

判断是否是NUMA导致的CPU分层现象,可以通过查看NUMA命中率来确认。常用的是使用numastat命令来查看目前NUMA的使用状态,默认numastat是整机的内存状态,加入-p可以指定某个单一业务进程,输出内容和结构都是如下表:

截屏2025-07-04 11.54.06.png

在这其中我们重点关注其中前三个指标:

  • numa_hit: 表示内存成功地按预期在该节点上分配。
  • numa_miss: 表示尽管进程偏好某个不同的节点,内存却被分配到了该节点。每个 numa_miss 都对应一个在其他节点上的 numa_foreign。
  • numa_foreign: 表示本应分配到该节点的内存,实际上被分配到了其他节点。每个 numa_foreign 都对应一个在其他节点上的 numa_miss。

以使用 numastat 输出的 numa_miss 和 numa_hit 数据。NUMA miss 率通常表示为所有内存分配中未命中的比例,公式如下:

NUMA的读写数据可以通过Linux提供的资源控制接口(User Interface for Resource Control feature)来观察。具体使用方法首先要查看CPU是否支持相关参数。Lscpu命令查看CPU是否支持相关功能。 CPU的Flag中需要存在cat_l3和cdp_l3字段

# lscpu | grep -E "cat_l3|cdp_l3"
Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca
cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht 
…
epb cat_l3 cdp_l3 invpcid_single
…..
cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts

然后需要使用以下命令挂载文件系统和支持功能:

mount -t resctrl resctrl [-o cdp] /sys/fs/resctrl

在挂载之后,我们可以进入/sys/fs/resctrl/mon_data目录下

截屏2025-07-04 11.58.45.png

其中_00和_01等就代表这不同的NUMA。mbm_local_bytes和mbm_total_bytes分别代表着读写本地NUMA域的数据和读写所有内存的数据。对于单个NUMA的命中率可以通过一下公式计算:

这种方法可以用来做系统的长期监控,但是如果采用这种方法判断NUMA的使用状态有个点需要注意,就是这些计数器可能会溢出,长期监控时需要定期读取并计算差值。

如果查看到某些CPU分层现象的机器,存在明显的NUMA miss率过高,便可以尝试通过合理的NUMA配置,来缓解CPU分层现象。

3.3. 解决思路

在观察到NUMA miss率指标异常后,可以通过CPU绑定的方式,确认NUMA的影响。CPU绑定可以使得业务始终跑在单一NUMA上,更好地利用好NUMA的特性,从而充分释放CPU的性能。

具体的绑定操作可以如下,首先通过lscpu查看CPU和NUMA的关联关系。

#lscpu 
21:04:18
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
...
...
NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38
NUMA node1 CPU(s):     1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39

在进程启动前可以供过numactl来指定进程采用的NUMA节点和CPU,如只在节点0的CPU上跑节点0:

numactl --cpunodebind=0 --membind=0 ./your_program

对于容器内的业务,也可以通过cgroup的方式来绑定业务到指定NUMA的CPU,指定业务只在单一NUMA的CPU列表中调度。

echo "1,3,5,7,9"  >  /sys/fs/cgroup/cpuset/业务容器名称/ cpuset.cpus

通过以上方式,便可以保证业务实例只在指定NUMA内部调度,从而充分发挥Local node的快速优势。

值得注意的是,并不是所有的业务均适合绑定NUMA的方式,假如业务的单个实例内存要求已经超过了单一NUMA节点的大小范围,这时绑定NUMA可能就带不来什么收益了,反而可能引发内存不足的潜在风险。

如果对于业务内存需求较大,但是工作集的热点内存数据大多仍旧集中在单一NUMA节点范围内部,且不会频繁调度到别的节点的业务,可以Linux kernel的NUMA Balancing功能来进行优化。具体通过如下方式开启:

echo 1 | sudo tee /proc/sys/kernel/numa_balancing

如果需要永久开启,保证机器重启之后依旧生效。则需要编辑 sysctl 配置文件/etc/sysctl.conf,在文件中添加以下内容:

kernel.numa_balancing = 1

然后执行以下命令:

sudo sysctl -p

该功能会把进程频繁访问的内存页迁移到本地NUMA,或者把当前进程迁移到访问内存所在的NUMA节点,通过此种方法来减少跨节点访问的延迟。

但是整个过程需要牵扯到内存或进程的迁移,如果进程节点间调度频繁或访问内存是大块儿顺序、跨多个线程共享的场景,NUMA balancing就不太合适了,对于这种情况下,可以优先采用 NUMA interleave 策略,具体设置方式如下:

numactl --interleave=all ./your_program

这种方式可以保证NUMA的均衡使用,充分利用多NUMA节点的内存带宽,提升吞吐,同时避免绑定NUMA下单个节点的内存不足或者本地优先策略导致部分部分线程频繁远程访问,造成业务性能抖动。

具体采用哪种NUMA策略来缓解分层现象,需要依赖业务逻辑和NUMA miss率等观测性指标来进行抉择。

4. Cache问题场景

4.1. 问题描述

Cache造成的性能差异则发生在不同型号的CPU之间,由于不同型号 CPU 在硬件设计和缓存架构上的差异,同一份业务代码在不同机型上会产生不同的缓存命中率,从而导致性能表现出现差距。典型的CPU在不同层级cache的访问速度差异如表1所示。

图片

表1 缓存命中与未命中的延迟差异

Cache造成的性能影响最直接在于CPU本身的Cache大小,如Intel i7-6700为例,L3 cache 的大小为8 MB。相比之下,AMD Ryzen 5800X拥有 32 MB 的L3 缓存。当运行一个工作集为10 MB的应用程序时,5800X则能完全容纳该工作集,将会跑出和理论算力相同的结果,而 i7-6700(L3缓存8 MB)会因为容量不足频繁触发缓存行替换,导致较高的Cache miss,而这会导致明显的性能劣化。

另一方面,应用程序本身的固定性也加剧了性能分层。由于一次编译的程序难以兼顾所有处理器特性,不同架构间的执行效率存在天然差异。例如,默认编译选项(如-xHost)偏向生成面向机器本身指令集的代码,这些指令在不同架构上,可能需要拆分为更多微操作,导致指令密度下降、引发更高的Cache Miss率,拉低整体吞吐率。

在混部场景下,不同业务的特性不同还有可能带来Cache的干扰问题。这个具体原因在于现代CPU的L3 Cache往往是多个核共享(Intel 通常是整颗物理CPU共享L3 Cache,AMD则是多个核作为一个CCD组共享L3 Cache),当某个业务应用如果需要读写大量L3 Cache,则会影响同一个CPU上别的业务,造成别的业务也频繁产生Cache miss,导致性能下降。

4.2. 指标反馈

Cache指标比较多,通常分为多层,L1,L2和L3(也称为LLC)cache,通常来说我们关注的指标为L3 cache的命中率,具体可以利用perf命令来抓取机器的机器的cache命中率。如下:

# perf stat -a -e LLC-load-misses,LLC-loads   -- sleep 10

Performance counter stats for'system wide':

        2,439,039      LLC-load-misses           #   28.50% of all LL-cache     
        
accesses

        8,558,008      LLC-loads 
        
      10.001813346 seconds time elapsed

Perf可以直观的给出cache 命中率,就是其中LLC-load-misses后边的数字。尽管perf的观测能力非常强大,但是其输出的结果简单,并没有对不同的进程和CPU运行情况进行分类展示,其采样频率也比较高,性能损耗较大,通常用于debug的调试场景。

在生产环境中,还有一个更加用户友好的工具llcstat。llcstat是一个基于 eBPF 的工具,相较于perf其采样频率更低,性能损耗更小,且能够汇总进程上下文信息。

截屏2025-07-04 12.01.00.png

它可以在内核态直接收集数据,并按进程和 CPU 聚合显示各项指标,如 PID、进程名称、缓存引用次数、缓存未命中次数以及缓存命中率,从而能够快速、直观地诊断和定位缓存瓶颈问题,非常适用于线上环境的性能监控和故障排查。

我们可以通过观察指定业务的Cache 命中率,来排查是否是Cache导致的分层现象。

4.3. 解决思路

Cache miss导致的CPU分层现象,本质上还是硬件结构带来的差异,很难彻底消除。问题的核心在于编译的可执行文件是相对固定的,而机器硬件结构存在差异。

处理这类问题有一个较为通用的缓解方法。就是我们在不同类型CPU运行业务时,尽量在该CPU上重新编译一遍,这样编译器会更多地考虑和利用目标机器的指令集、微架构和cache结构。

不过Cache miss的缓解最优解其实是在业务代码层次,如读取数组时尽量按行读取而不是按列。将数据结构对齐到缓存行边界,避免由于数据跨越多个缓存行。确保每个线程操作的数据分布在不同的缓存行中,减少缓存一致性协议的开销等等。

对于Cache干扰的场景,我们可以通过resctrl进行Cache隔离的方式来处理。首先要根据3-2对resctrl进行条件检查和挂载。然后查看L3 Cache的结构:

#cat /sys/fs/resctrl/schemata
L3:0=fffff;1=fffff

可以看到该机器有两个L3 Cache,每个是0xfffff=20路(ways)。

然后我们就可以建立资源控制组:

#sudo mkdir /sys/fs/resctrl/mygroup

编辑 schemata 文件,设置缓存和带宽的分配。例如,限制 L3 缓存只使用4路:

#echo "L3:0=0x0000f;" | tee /sys/fs/resctrl/mygroup/schemata

最后将任务或 CPU 分配到资源组:

#限制任务进程
#echo <PID> | tee /sys/fs/resctrl/mygroup/tasks

#限制CPU
echo 0-3 | tee /sys/fs/resctrl/mygroup/cpus

在我们给指定大量读写L3 Cache的任务进行隔离之后,也许会略微减少这类任务的速率,但是保证了其他混部任务不受干扰,同时提升系统总体的Cache利用率,保证了业务的稳定可预期。

5. 降频问题场景

5.1. 问题描述

CPU降频的现象往往出现在特定的CPU和业务中。但是其影响相对别的原因会更大一些,尤其是在混部场景,当某一业务导致了CPU降频现象,该机器上所有任务的执行速度都会受到影响。在我们的场景中,最常见的有两种现象导致的CPU降频:

一种是负载过高导致的CPU降频,现代CPU通常采用动态频率调节技术(如Intel的Turbo Boost或AMD的Precision Boost),在部分核心工作时可以提升频率,然而当所有核心同时高负载时,由于其总功耗一定,这时CPU的总体频率通常会降低。

另一种是AVX指令导致的CPU降频。AVX(Advanced Vector Extensions,高级向量扩展)是Intel 提出的SIMD(单指令多数据)指令集扩展。在当前的AVX实现中,算术单元在小范围内需要大量的数据路径进行协作,这导致支持AVX2和AVX-512的处理器在执行AVX指令时,必须降低处理器频率以确保稳定性。当应用程序大量运行AVX指令时,会导致所在核心的频率降低,进而影响到服务器的整体性能。 CPU 降频意味着降低意味着单位时间内能完成的计算量减少,这是对于计算能力的直接削弱,自然会产生CPU分层现象。

5.2. 指标反馈

服务器的性能通常通过P-State(Performance State)和C-State(CPU Power States)来进行CPU功耗和频率的管理,其中P-State决定 CPU 如何选择不同频率而C-State决定 CPU 在空闲时是否进入低功耗休眠状态。

我们首先可以查看当前CPU的P-State,确认其是否符合预期。

#cat cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governorperformance
performance
……
performance
performance

调节器(Governor)决定如何调整频率,可选项有:

  • performance(一直保持最高频率)
  • powersave(尽可能低频运行)
  • ondemand(负载高时升频,低时降频)
  • schedutil(结合调度器调整频率)

C-State 最直接的控制方式是 在 BIOS/UEFI 中启用或禁用 某些级别的 C-State。C-State有多种级别,C0-Cn,其中C0代表正常运行,C1-Cn代表CPU idle状态的不同休眠程度,C后面的数值越高,CPU睡眠的越深,功耗也被降低的越多,但是恢复到运行态需要的时间也越多。可以通过以下方法查看C-State的参数:

#cat /sys/module/intel_idle/parameters/max_cstate
1

这个文件代表当前驱动允许的最大C-State等级,如上所示,当前机器最多允许C1程度的休眠。

检查产生CPU分层现象的机器是否存在降频现象需要一段时间的频率收集和比对。可以通过一下几种方法来查看。

第一种方法是直接查看硬件监控面板。首先最简单有效的方法是查看moni 面板上的CPU主频信息,可以直接对比不同机器的CPU频率和单一机器不同时间的CPU频率数据。如图4所示。

图片

图4 CPU的主频图

第二种方法是读取 /proc/cpuinfo 文件。如果机器并没有部署相关的监控面板,可以通过执行 cat /proc/cpuinfo | grep MHz 命令,可以获取每个逻辑CPU核心的实时频率。该方法的优势在于无需额外工具,输出结果直接反映CPU的瞬时状态,但由于频率可能因节能技术(如Intel SpeedShift或AMD Cool'n'Quiet)动态调整,建议结合 watch 命令(如 watch -n 1 'cat /proc/cpuinfo | grep MHz')进行持续监控,以观察频率波动趋势。

截屏2025-07-04 12.02.59.png

第三种方法是使用 cpupower 工具。执行 cpupower -c all frequency-info 可获取更全面的信息,包括当前频率(current CPU frequency: 当前频率)、硬件支持的频率范围以及调频策略等。若需实时监控,类似的也是可通过 watch 命令定期查询输出中的 current CPU frequency 字段。

# cpupower -c all frequency-info
analyzing CPU 0:
  driver: intel_pstate
  CPUs which run at the same hardware frequency: 0  
  CPUs which need to have their frequency coordinated by software: 0  
  maximum transition latency:  Cannot determine or is not supported.  
  hardware limits: 800 MHz - 3.80 GHz
  available cpufreq governors: performance powersave
  current policy: frequency should be within 800 MHz and3.80 GHz.  
                  The governor "performance" may decide which speed to use 
                  within this range. 
  current CPU frequency: Unable to call hardware
  current CPU frequency: 2.90 GHz (asserted by call to kernel) 
  boost state support:  
    Supported: yes  
    Active: yes

正常来说,查看监控面板来分析CPU频率对于CPU分层的现象最为方便,若仅需快速检查当前机器的状态,/proc/cpuinfo 最为便捷;但是如果需获得更详细的信息,还是推荐使用 cpupower。

5.3. 解决思路

在确保散热的前提下,主要可以通过锁定CPU频率的方法来解决CPU的降频导致的业务分层现象。具体可以从操作系统和硬件两个层面来锁定CPU的频率。操作系统层面可以使用以下方法来配置。

截屏2025-07-04 12.04.00.png

通过硬件锁频则通常需要进入BIOS找到Package Power Limit Contol相关的选项,设置为指定频率,不过不同厂商的设置方式大相径庭,具体操作方法建议查阅主板的相关说明,或者参考厂商的技术支持文档。

面对CPU降频导致的分层现象,前期可以采用操作系统锁频的方式,灵活快捷,无需重启,适合临时问题验证,但可能被系统温控覆盖;确认问题之后后期还是建议BIOS锁频,更稳定彻底,适合长期使用,适合生产环境持久保障。

虽然CPU锁频可以避免CPU 频率波动会带来性能抖动,提升系统的稳定性。但是另一方面,高频运行意味着持续高功会带来更多的电量和散热需求,这样将会带来电费成本的增加,可以根据业务实际情况做取舍。

6. 总结和展望

面对数据中心异构硬件环境合池带来的管理挑战,缓解CPU分层现象是实现算力统一调度与高效利于的必经之路。我们从NUMA、Cache和CPU频率方面分别讨论了其具体问题、指标反馈、以及对应的缓解方法。旨在缓解因计算资源差异导致的资源合理分配问题,进一步提升了合池带来的经济收益。

但正如前文所示,CPU分层现象的原因复杂多样,牵涉到太多细枝末节。目前开源内核社区对异构混部场景的讨论和关注仍比较有限,缺乏针对性的分析工具和解决方案,使得此类问题在实际生产环境中的定位和优化极具挑战性。同时,硬件架构与系统软件的持续演进也不断带来新的变量,进一步加剧了问题的复杂性。可以说,缓解机器的CPU分层现象如同画一个完美的圆,现实中我们无法画出一个完美的圆,但是我们可以朝着这个完美圆的方向砥砺前行。

下一步,我们会继续专注在异构机器混部的场景,与上下游团队紧密协作,共同定义关键问题并制定解决策略;同时,依托多维度的数据反馈,对方案进行动态修正与演进,力求探索出一条最契合B站业务特性的路径。

-End-

作者丨弓长墨杨、飛熊