本文探讨了zStorage分布式块存储系统在特定环境下使用FIO工具测试时出现的IO延迟问题,通过对问题的定界和深入分析,最终找到了问题所在并提供了解决方案。
近期,zStorage系统在海光+麒麟+E810网卡环境下使用FIO工具测试4K单并发随机读/写IO时,延迟达到4ms,而使用Mellanox网卡时延迟正常。
根据Ftrace信息,发现4ms的延迟出现在Host端的内核处理上,与APIC定时器和软中断处理机制有关。
通过分析IO处理流程,确定问题出在__raise_softirq_irqoff函数上,提出使用不带下划线的raise_softirq_irqoff或Tasklet来触发延迟任务作为解决方案。
使用Tasklet触发延迟任务后,时延降低至130us,解决了4ms延迟的问题。
注:本文内容引用自张洋老师的知乎文章
https://zhuanlan.zhihu.com/p/735757082,他
是一位存储研发专家。
问题现象和背景
近期,zStorage分布式块存储系统在海光+麒麟
+E810网卡环境下,使用FIO工具测试4K单并发随机读/写IO时,延迟达到4ms。而这里唯一的变量是E810网卡;如果采用Mellanox网卡,在同样的测试用例下,IO延迟约为100us左右。那么问题出在网卡吗?还是另有原因?以下是分析和探索的过程分享。
问题定界
要分析上述高时延问题,首先需要对问题进行定界:是zStorage存储软件的问题,还是Host端的问题?针对这一问题,我们做了以下几件事情:
-
- 时延分析
:zStorage FrontEnd从收到IO到应答IO给Host,耗时 < 100us,符合预期。这个实验表明问题大概率不在存储端,但仍不能完全断定问题在Host端。
-
-
- 更换HOST:重新使用一个内核版本为5.10的系统,进行相同的测试用例,时延恢复正常。这个结果至少说明,更换内核可以解决问题,问题大概率与内核有关。
-
-
- Ftrace跟踪分析:在出问题的HOST上开启Ftrace,跟踪nvmf和rdma相关函数。发现4ms的时延确实出现在Host端的处理上。如下图所示:在58225.458457这个时间点,Host的IB驱动已经收到了存储节点的ACK应答,但直到58225.462423这个时间点才调用
nvme_rdma_send_done
。这个实验表明,确实是Host端的内核存在一个4ms的延迟。
4ms延迟流程深究
根据Ftrace的信息,可以看到在4ms后,由
smp_apic_timer_interrupt
触发,完成了消息的发送。
在 Linux 内核中,smp_apic_timer_interrupt 是处理APIC(Advanced Programmable Interrupt Controller)定时器中断的中断处理程序。当该中断触发时,它可以调用定时器相关的处理程序,通常与调度器、进程切换、软中断
等内核机制相关。APIC 定时器是每个 CPU 的本地定时器,用于周期性地触发中断,从而执行某些周期性的任务。
具体来说,这个APIC定时器的频率较低,通常在1000Hz以下,而当前出问题的Host为250Hz,因此每4ms调度一次,这与IO延迟4ms是相吻合的。然而,这个频率是在内核编译时确定的,修改起来并不容易,且直觉上问题不太可能出在这里。毕竟,为了解决这个问题,不可能将频率改为100万Hz。那么,为什么IO会在
smp_apic_timer_interrupt
的调度流程中完成呢?IO真正的完成应该是在什么流程中呢?
继续探究IO未及时处理的原因
继续使用Ftrace跟踪更多详细的信息。
在
ib_cq_completion_softirq
的下一个函数调用是
__raise_softirq_irqoff
。翻阅内核源码后,发现
irq_poll_sched
这个函数至关重要。它负责调度软中断处理,并与IO完成的路径密切相关。进一步分析
irq_poll_sched
的调用时机和作用,可能揭示出为何IO在软中断处理链中被延迟触发。
这意味着,
irq_poll_sched
函数并不希望在当前流程中立即处理I/O,而是将当前I/O加入到CPU的延迟任务处理队列中,等待延迟处理。然而,实际情况是处理延迟了4ms,这个延迟确实过长了。注意这一行代码:
__raise_softirq_irqoff(IRQ_POLL_SOFTIRQ);
。
__raise_softirq_irqoff()
触发了指定类型的软中断,这里是
IRQ_POLL_SOFTIRQ
,用于调度一个软中断处理函数来处理加入轮询队列
的I/O任务。
接下来,进一步查看内核源码,以分析
IRQ_POLL_SOFTIRQ
如何调度以及为什么延迟长达4ms?
IRQ_POLL_SOFTIRQ
这个软中断是与
irq_poll_softirq
函数绑定在一起的。这意味着,一旦使用
__raise_softirq_irqoff
触发了软中断,应该在短时间内调用
irq_poll_softirq
,以处理刚才的I/O完成。然而,在实际情况中,I/O处理延迟了4ms,这表明在软中断的调度和处理之间存在瓶颈或延迟。
对IO处理流程稍作总结
ROCE网卡的中断处理流程已经梳理清楚: