企业存储技术 · 10月16日

探索与解决:Intel E810网卡的4ms单并发IO延迟问题

注:本文内容引用自张洋老师的知乎文章 https://zhuanlan.zhihu.com/p/...,他是一位存储研发专家。

问题现象和背景

近期,zStorage分布式块存储系统在海光+麒麟+E810网卡环境下,使用FIO工具测试4K单并发随机读/写IO时,延迟达到4ms。而这里唯一的变量是E810网卡;如果采用Mellanox网卡,在同样的测试用例下,IO延迟约为100us左右。那么问题出在网卡吗?还是另有原因?以下是分析和探索的过程分享。

image.png

问题定界

要分析上述高时延问题,首先需要对问题进行定界:是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的延迟。

image.png

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真正的完成应该是在什么流程中呢?

image.png

继续探究IO未及时处理的原因

继续使用Ftrace跟踪更多详细的信息。

image.png

ib_cq_completion_softirq的下一个函数调用是__raise_softirq_irqoff。翻阅内核源码后,发现irq_poll_sched这个函数至关重要。它负责调度软中断处理,并与IO完成的路径密切相关。进一步分析irq_poll_sched的调用时机和作用,可能揭示出为何IO在软中断处理链中被延迟触发。

image.png

image.png

这意味着,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?

image.png

IRQ_POLL_SOFTIRQ这个软中断是与irq_poll_softirq函数绑定在一起的。这意味着,一旦使用__raise_softirq_irqoff触发了软中断,应该在短时间内调用irq_poll_softirq,以处理刚才的I/O完成。然而,在实际情况中,I/O处理延迟了4ms,这表明在软中断的调度和处理之间存在瓶颈或延迟。

对IO处理流程稍作总结

ROCE网卡的中断处理流程已经梳理清楚:

  • irdma 发送数据到存储节点,使用 RDMA 协议传递数据。
  • 存储节点的网卡收到数据后,在大约 10 微秒内返回 ACK,表明数据接收完成。
  • irdma 通过网卡中断收到 ACK 后,开始处理当前的 CQE。它将 CQE 传递给 CPU 的 irq_poll 机制,并通过 __raise_softirq_irqoff(IRQ_POLL_SOFTIRQ) 触发另外一个软中断。
  • 这个时候,irq_poll 的软中断机制应该被立即处理,快速响应以完成 CQE 处理。
  • 实际上,软中断并未在触发后立即被处理,而是等到 4 毫秒后由 smp_apic_timer_interrupt 触发。这导致了预期外的延迟。

__raise_softirq_irqoff为什么未及时触发处理软中断?

经过一番查找,终于找到了答案:https://github.com/torvalds/l...

image.png

这段描述解释了为何在特定场景中,需要使用raise_softirq_irqoff()而不是__raise_softirq_irqoff()来触发软中断,特别是在非中断上下文中(如工作队列或内核线程中的软中断调度)。

image.png

简单来说,某些场景下__raise_softirq_irqoff是不生效的。而raise_softirq_irqoff函数是对__raise_softirq_irqoff的封装,如果当前不在中断上下文,则会调用一个wakeup_softirqd函数,唤醒ksoftirqd进程以立即处理软中断。

image.png

结论

至此,问题原因已经很清晰了,就是将__raise_softirq_irqoff改成raise_softirq_irqoff即可,删除两个下划线。然而,在不修改内核驱动的情况下,应该如何解决这个问题呢?毕竟在同样的HOST上,Mellanox卡没有出现问题。

尝试修改irdma驱动源代码

IRDMA:这是Intel特定的RDMA驱动,专门处理支持IRDMA的Intel网卡,如E810。它处理RDMA连接的管理、数据传输的加速,并与IBCORE模块协作完成数据的高效传输。

实际上还是有一些思路可行,例如:

  • 可否在irdma驱动中增加一行代码,使用不带下划线的raise_softirq_irqoff?编译驱动时却报错:WARNING: "raise_softirq" [/root/irdma-1.15.11/src/irdma/irdma.ko] undefined! 未再继续深究。
  • 使用Tasklet来触发延迟任务。 Tasklet 是一种基于 SoftIRQ 的延迟执行任务机制,专门为简单、短时间内完成的任务设计。它本质上是一个简化的 SoftIRQ,开发者可以通过 tasklet 将不紧急的工作推迟到稍后执行。TASKLET_SOFTIRQ 是 Linux 内核中的软中断(SoftIRQ)机制之一,专门用于延迟执行轻量级任务的框架。它通过一种称为tasklet的机制来处理可延迟执行的任务,适用于需要在较短时间内完成的工作,而不需要立即执行,并且不需要中断整个系统调度。
    经过测试,该方法有效,时延为130us,解决了4ms延迟的问题。

image.png

  • 可否在irdma驱动中增加wakeup_softirqd,以触发软中断处理?——未尝试。
  • 其他实验中,导致了内核崩溃,或者RDMA连接不上等问题。——未采用。

扩展阅读:企业存储技术》文章分类索引更新(微信公众号合集标签)

:本文只代表作者个人观点,与任何组织机构无关,如有错误和不足之处欢迎在留言中批评指正。进一步交流,可以加我的微信:490834312。如果您想在这个公众号上分享自己的技术干货,也欢迎联系我:)

END

作者:张洋
原文:企业存储技术

推荐阅读

欢迎关注企业存储技术极术专栏,欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
5614
内容数
263
关注存储、服务器、图形工作站、AI硬件等方面技术。WeChat:490834312
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息