【运维案例】fio压测云盘性能,多盘场景arm架构性能是x86的一半

背景描述:

基于MLX BF2卡的弹性裸金属场景网络和存储性能测试。在FIO测试7:3混合读写场景,压测远端存储盘,压测4块盘时性能正常,压测8块盘时,性能下降明显。

存储方案模型

存储后端通过BF2模拟的virtio-blk设备,访问远端的云盘。

测试环境:

服务器 鲲鹏920 6426
OS CTyunOS
内核 4.19
DPU卡 Mellanox BF2

原因分析

进一步分析性能瓶颈发现,在8盘同时压测情况下,中断都分配到0、32、64核心,处理中断的CPU被压满了,导致单核响应中断出现瓶颈。同样情况下,对比X86环境,中断较ARM场景会分散到多个CPU处理,性能达标。

下图中virtioX-req表示不同的设备盘对应的中断,当前环境下设置的MSI-X数为3,对应三个中断队列。数据的三列分别表示中断号、中断CPU、中断次数,可以看到所有盘的中断都集中在了0、32、64的核心上(分别为Numa0、Numa1、Numa2的第一个核)。
中断信息

同样情况下,对比X86的中断亲和性配置文件,中断绑核是散列的。 客户使用的OS尝试修改亲和性文件,修改不成功。

尝试手动修改中断亲和性,有类似如下的报错:

经分析后,此报错确认是该LPI中断带了IRQD_AFFINITY_MANAGED flag,用户态无法设置亲和性,只能由内核分配。该flag为内核上游社区在4.8版本加入。

ARM架构下在映射LPI中断时,ITS(Interrupt Translation Service)驱动程序会从中断的亲和性列表和在线CPU的交集中选择第一个cpu,在大多数情况下是CPU0。如果多个中断亲和性被设置为cpu 0 - cpu xx,那么这些中断会集中送到cpu0上,导致cpu0负载过高,性能较差。由于ARM与x86架构下中断控制器差异,ARM架构LPI中断和X86 APIC中断实现机制不同,x86在APIC中断上实现了负载均衡,因而未出现该问题。

解决方法:

通过NV网卡工程师交流获悉,arm架构下CentOS 8.5 stream版本不存在中断无法散列问题。进一步验证,在CentOS 8.5 kernel-4.18.0.348下验证virtio-blk中断无法正常散列,CentOS 8.5 stream kernel-4.18.0.486验证virtio中断散列正常。初步定界2个内核版本间存在相关修复patch,结合中断流程机制,锁定LPI中断等相关patch。

2f13ff1d1d (“irqchip/gic-v3-its: Track LPI distribution on a per CPU basis”)

c5d6082d3 (“irqchip/gic-v3-its: Balance initial LPI affinity across CPUs”)

1dc440355 (“crypto: hisilicon/zip - add a work_queue for zip irq”)

经过分析,以上补丁主要通过找到“负载最少”的CPU(即映射到它的LPI中断较少的CPU)来放置中断,可以分散单个CPU处理LPI中断的性能开销,避免多个LPI中断集中在少数核上处理。

补丁作用范围和模块

该补丁只修改了ITS中断模块的驱动文件drivers/irqchip/irq-gic-v3-its.c,影响LPI中断在哪个CPU上处理,具体如下:

  • 功能接口:its_set_affinity()和its_irq_domain_activate()
  • 中断类型:managed 和unmanaged 的LPI中断

硬件平台:NUMA或者非NUMA平台,并且是多核平台

  • 性能:降低某些CPU上的LPI中断负载,特别是能有效改善managed LPI中断的性能问题,因为managed LPI中断无法在用户态配置亲和性,而unmanaged LPI中断本身可以在用户态配置亲和性。

补丁实现原理分析

跟踪每个CPU的LPI中断数量

为了改善CPU之间的LPI分布,需要跟踪分配给CPU的LPI数量,包括managed中断和unmanaged中断:

  1. managed中断和unmanaged中断都用一个per cpu的计数器进行LPI中断数量计数

  1. 在its_set_affinity()函数设置LPI中断亲和性或者its_irq_domain_activate()激活一个LPI中断时根据中断managed属性进行相关CPU的相关中断计数器加1
  2. 在执行its_irq_domain_deactivat()函数停止分发一个LPI中断时根据中断managed属性进行相关CPU的中断计数器减1

不同CPU间进行LPI中断负载均衡

在its_irq_domain_activate()激活一个LPI中断时或者在设置中断亲和性时没有强制设置亲和性mask时,从可选目标CPU集合中选择一个LPI中断负载最轻的CPU。

在设置中断亲和性时,managed中断和非managed中断目标CPU不同:

  • managed中断:分配的CPU mask和在线CPU mask的交集
  • 非managed中断
    • 中断绑定到NUMA节点:目标CPU由亲和性mask、节点mask决定
    • 中断没有绑定到NUMA节点:目标CPU由亲和性mask和在线mask决定

最后,不管managed中断还是unmanaged中断,都通过cpumask_pick_least_loaded()函数从可选择的目标CPU集合中选择LPI中断数量最少的CPU,实现LPI中断的负载均衡,该函数实现原理为:

遍历所有可选CPU,根据managed属性从per cpu的相应计数器中获取每个可选CPU的LPI中断数量,然后从其中选择中断数量最少的CPU。

补丁相关维测接口

设置日志级别允许pr_debug输出时,可以打印为虚拟中断号irq选择的最轻LPI中断负载CPU,以及可选CPU集合aff_mask,便于分析和调试。

补丁验证测试

基于搭建的openEuler20.03 SP3环境,回合相关补丁,重新编译内核后,LPI中断可散列在各CPU核心上,中断瓶颈问题得到解决。Fio在8盘场景测试,补丁回合后,初步验证IO性能提升约60%。

资料参考

https://lore.kernel.org/all/20200316115433.9017-1-maz@kernel.org/

https://lore.kernel.org/all/20200316115433.9017-2-maz@kernel.org/

https://lore.kernel.org/all/20200316115433.9017-3-maz@kernel.org/

https://lore.kernel.org/all/87h80q2aoc.fsf@nanos.tec.linutronix.de/

1 个赞