《存储IO路径》专题:块设备层多队列blk-mq架构

我们想象一下,你是一个餐厅的厨师,你要准备很多不同的菜肴,而每种菜肴需要不同的食材和烹饪时间。如果每道菜都按照需要的顺序来准备,那么你的工作效率一定会非常低。为了提高效率,你会怎么做呢?

在linux架构中,Multi-Queue Block Layer就像是一个聪明的餐厅管理员,它可以让厨师们同时处理多个订单,而不用等待前面的订单完成。这个机制在Linux内核中实现了多个I/O调度队列,每个队列处理特定类型的I/O操作。这样,当一个进程发出I/O请求时,Multi-Queue Block Layer可以将请求分配到对应的队列中,让I/O操作并行执行,大大提高了系统的性能。

在Linux中,blk-mq架构是block layer的一种改进,它通过支持多个I/O调度队列来提高系统的并发性和响应性。Multi-Queue Block Layer在内核版本3.14之后引入,并在后续版本中得到了进一步的发展和完善。

在blk-mq架构中,每个块设备都维护了多个I/O调度队列,每个队列对应于一个特定的优先级。当系统接收到I/O请求时,根据请求的优先级将其分配到对应的队列中。每个队列都采用自己的I/O调度策略,比如先进先出(FIFO)、最短作业优先(SFS)等。这种机制可以使得不同优先级的I/O请求能够得到更好的处理和响应。

下面是一个简单的示例代码,展示了Multi-Queue Block Layer的基本原理:

复制代码
#include <linux/blkdev.h>  
  
/* 初始化块设备 */  
struct gendisk *disk;  
  
/* 初始化块设备分区 */  
struct hd_struct *part;  
  
/* 初始化块设备请求队列 */  
struct request_queue *queue;  
  
/* 初始化块设备I/O调度器 */  
struct elevator_type *elevator;  
  
/* 初始化I/O调度参数 */  
elevator_param_t elevator_params[];  
  
/* 初始化I/O调度队列 */  
struct blk_queue_layer queue_layer;  
  
/* 分配I/O调度队列 */  
queue_init_queue(&queue_layer, disk, part, queue, elevator, elevator_params);

在上述代码中,我们首先初始化了块设备、分区、请求队列和I/O调度器等组件。然后,我们通过调用queue_init_queue函数来初始化一个blk_queue_layer结构体,该结构体表示一个I/O调度队列层。该函数接受多个参数,包括块设备、分区、请求队列、I/O调度器和I/O调度参数等。在函数内部,会根据指定的参数创建一个新的I/O调度队列,并将其添加到对应的块设备的I/O调度队列层中。

在传统的Linux系统中,块设备层和IO调度器主要是针对HDD(hard disk drivers)设计的。由于HDD设备的随机IO性能很差,吞吐量大约是几百IOPS(IOs per second),延迟在毫秒级,所以当时IO性能的瓶颈在硬件,而不是内核。但是,随着高速SSD(Solid State Disk)的出现并展现出越来越高的性能,百万级甚至千万级IOPS的数据访问已成为一大趋势,传统的块设备层已无法满足这么高的IOPS需求,逐渐成为系统IO性能的瓶颈。为了适配现代存设备(高速SSD等)高IOPS、低延迟的IO特征,新的块设备层框架Block multi-queue(blk-mq)应运而生。

  • Multi-Queue Block Layer分为两层,Software Queues和Hardware Dispatch Queues.
  • Softeware Queues是per core的,Queue的数目与协议有关系,比如NVMe协议,可以有最多64K对 IO SQ/CQ。Software Queues层做的事情如上图标识部分。
  • Hardware Queues数目由底层设备驱动决定,可以1个或者多个。最大支持数目一般会与MSI-X中断最大数目一样,支持2K。设备驱动通过map_queue维护Software Queues和Hardware Queues之间的对接关系。
  • 需要强调一点,Hardware Queues与Software Queues的数目不一定相等,上图1:1 Mapping的情况属于最理想的情况。

在实际应用中,blk-mq架构可以显著地提高系统的并发性和响应性。通过支持多个I/O调度队列,它可以更好地处理不同优先级的I/O请求,并根据不同的I/O负载情况和系统配置进行调优和优化,以获得更好的性能和响应性。

blk-mq的映射关系是指将软件队列(software queue)映射到硬件派发队列(hardware dispatch queue)的机制。这种映射关系是通过固定的映射关系来实现的。

在blk-mq架构中,每个硬件队列都对应一个或多个软件队列,这个对应关系是在驱动初始化时通过配置来设定的。通常情况下,每个硬件队列会对应多个软件队列,这种映射关系可以避免请求队列锁竞争和远端内存访问问题,从而提高Block Layer的IOPS吞吐量。

当用例空间向块设备执行IO操作时,BLK-MQ会存储和管理这些IO请求,并在用户空间、文件系统和块设备驱动程序之间扮演中间件的角色。BLK-MQ通过软件阶段队列和硬件分配队列来实现请求的调度和管理。当请求到达块设备层时,它将会尝试最短路径,即直接发送到硬件队列。

然而,存在两种情况不会这样做:

一是存在IO调度器则不能这样做;

二是如果我们想让请求合并也不行这样做。

这两个情况下请求将会被发送到软件队列。在软件队列中的请求处理之后,它将被放到硬件队列,后面即是硬件直接访问硬件处理这些请求。

blk-mq的映射关系解决了blk-sq架构中请求队列锁竞争和远端内存访问问题,极大的提高了Block Layer的IOPS吞吐量。同时,通过将软件队列映射到硬件派发队列,可以更好地处理不同优先级的I/O请求,并根据不同的I/O负载情况和系统配置进行调优和优化,以获得更好的性能和响应性。

相关推荐
微风中的麦穗28 分钟前
【MATLAB】MATLAB R2025a 详细下载安装图文指南:下一代科学计算与工程仿真平台
开发语言·matlab·开发工具·工程仿真·matlab r2025a·matlab r2025·科学计算与工程仿真
2601_9491465337 分钟前
C语言语音通知API示例代码:基于标准C的语音接口开发与底层调用实践
c语言·开发语言
开源技术1 小时前
Python Pillow 优化,打开和保存速度最快提高14倍
开发语言·python·pillow
学嵌入式的小杨同学1 小时前
从零打造 Linux 终端 MP3 播放器!用 C 语言实现音乐自由
linux·c语言·开发语言·前端·vscode·ci/cd·vim
毕设源码-朱学姐1 小时前
【开题答辩全过程】以 基于JavaWeb的网上家具商城设计与实现为例,包含答辩的问题和答案
java
mftang2 小时前
Python 字符串拼接成字节详解
开发语言·python
jasligea3 小时前
构建个人智能助手
开发语言·python·自然语言处理
kokunka3 小时前
【源码+注释】纯C++小游戏开发之射击小球游戏
开发语言·c++·游戏
C雨后彩虹3 小时前
CAS与其他并发方案的对比及面试常见问题
java·面试·cas·同步·异步·
ujainu3 小时前
Flutter + OpenHarmony 游戏开发进阶:主菜单架构与历史最高分持久化
flutter·游戏·架构·openharmony