Linux block multi-queue (blk-mq) 机制

        Multi-Queue Block IO Queuing Mechanism 是一种 API,可让快速存储设备通过排队并同时向块设备提交 IO 请求来实现每秒大量的输入/输出操作 (IOPS),有益于现代存储提供的并行性设备。 

背景

        从内核开发之初,磁硬盘一直是事实上的标准。 Block IO 子系统旨在为那些在进行随机访问时具有高惩罚的设备实现最佳性能,而瓶颈是机械运动部件,比存储堆栈上的任何层慢得多。这种优化技术的一个例子涉及根据硬盘磁头的当前位置对读/写请求进行排序。 然而,随着固态驱动器和非易失性存储器的发展,没有机械部件,也没有随机访问惩罚,能够执行高并行访问,堆栈的瓶颈已经从存储设备转移到了操作系统。为了利用这些设备设计中的并行性,引入了多队列机制。 前一种设计有一个单独的队列来存储带有单个锁的块 IO 请求。由于缓存中的脏数据和多个处理器的单一锁的瓶颈,这在 SMP 系统中不能很好地扩展。当不同的进程(或同一进程,移动到不同的 CPU)想要执行块 IO 时,这种设置也会遇到拥塞。取而代之的是,blk-mq API 生成多个队列,这些队列具有 CPU 本地的各个入口点,从而无需锁定。下一节将更深入地解释其工作原理。

操作过程

        当用例空间向块设备执行IO操作时,BLK-MQ会存储和管理这些IO请求,在用户空间、文件系统和块设备驱动之间扮演中间件的角色。

        BLK-MQ有两组队列:软件阶段队列和硬件分配队列。当前请求到达块设备层,它将会尝试最短路径,即直接发送到硬件队列。然而,有两情况不会这样做:一是存在IO调度器则不能这样做;二是如果我们想让请求合并也不行这样做。这两个情况下请求将会被发送到软件队列。

        在软件队列中的请求处理之后,它将被放到硬件队列,后面即是硬件直接访问硬件处理这些请求。然而,如果硬件没有足够的资源去接收更多的请求,blk-mq将会将这些请求放到临时队列,直到硬件有资源之后再发送。

软件阶段队列(struct blk_mq_ctx)

        块IO子系统在请求不能直接发送到驱动的时候将请求添加到软件阶段队列。一个请求即是一个或多个BIO。请求到达块层的数据结构为struct bio,块层会再构建一个数据结构,用于和块设备驱动交互。每个阶段队列都有它自己的锁并且队列数是基于每个CPU核或每个CPU结点。

        软件阶段队列可以用于合并具有相邻扇区的请求。比如,有三个请求“扇区3-6、扇区6-7、扇区7-9”,则可以全成一个请求“扇区3-9”。即使SSD/NVME的随机访问和连续访问有相同的时间,但是将多个连续访问合并会减少独立请求的个数。这个合并技术叫做“plugging”。

        除此之外,可以通过 IO 调度程序重新排序请求以确保系统资源的公平性(例如,确保没有应用程序遭受饥饿)和/或提高 IO 性能。

IO调度器

        块层有多个IO调度器,每个调度器都遵循启发式方法来提高 IO 性能。调度器是“可插拔的”(如即插即用),因为它们可以在运行时使用 sysfs 进行选择。调度只针对相同队列中的请求,因此它不能合并不同队列中的请求(多队列需要加锁并且会产生缓存垃圾,因此不支持),调度完成 之后,请求便可以发送到硬件了。最简单的调度器是"NONE"调度器,它只是将请求放到任意可以使用的软件队列中,不会进行任何重排序。当块设备开始处理硬件队列中的请求时(也叫做,运行硬件队列),映射到硬件队列的软件队列将会根据映射按顺序使用完。

硬件分发队列

        硬件队列(struct blk_mq_hw_ctx)是一个结构体,用于设备驱动映射提交队列(或者映射设备DMA环形BUFFER),并且是底层设备驱动用例请求前的最后一步块层提交代码。如果运行这个硬件队列,块层从关联的软件队列中移除请求分发到硬件。

        如果不能直接发送请求到硬件,它们将会被添加到一个请求链表上(hctx->dispatch),然后,等到下一次运行硬件队列时,首先从这个链表开发分发,确保公平分发。硬件队列的数量取决于硬件和它的驱动程序,但它不会超过系统的CPU核数。硬件队列阶段没有重排序功能,每个软件队列有一个可发送请求的硬件队列集合。

 注:完成请求的顺序即不是块层保证也不是设备协议保证,必须由更高层来保证,比如文件系统。

基于Tag的完成

        为了表示哪个请求已经完成,每个请求有一个整形ID,范围是0到队列深度。这个TAG是块层生成,后续底设备驱动也可使用。当前驱动完成一个请求,请求的TAG将被发送回块层去通知请求终结,避免了IO的线程查找。

你可能感兴趣的:(Kernel,block)