Linux磁盘I/O性能优化:从调度到缓存的核心设计解析
Linux磁盘的I/O调度是系统性能调优的一个重要组成部分,其核心目标在于根据存储设备的物理特性,合理的去规划I/O请求的顺序,减少无效操作导致性能问题。
0.引言
在前一篇文章中我们讲解了文件I/O与流的概念,帮助大家理解了上层的抽象设计。本文将深入更为底层的实现机制,探讨Linux如何高效访问磁盘的两大关键技术:磁盘调度算法和Page Cache。我们将分别从两个维度进行分析:一是I/O调度策略的优化,二是Page Cache的如何减少I/O操作。
1.磁盘I/O调度:减少寻道时间和延迟
Linux磁盘的I/O调度是系统性能调优的一个重要组成部分,其核心目标在于根据存储设备的物理特性,合理的去规划I/O请求的顺序,减少无效操作导致性能问题。因为调度的选择涉及设备的物理特性,所以我们来看常见的两种物理存储设备,然后再来去介绍不同调度算法:
1)机械硬盘(HDD):机械硬盘是传统的硬盘,其依赖于磁头移动和盘片旋转来实现读写,其寻道时间(磁头移动)和旋转延迟(盘片旋转)是其主要耗时,所以随机I/O性能远低于顺序I/O,这就要求调度算法要通过合并、排序等方式来减少磁头的移动。
2)固态硬盘(SSD):固态硬盘是由控制单元和存储单元组成,没有机械部件,所以寻道时间几乎可以忽略不计,也就是说它有着很好的随机I/O性能,但其存在擦写次数限制,和写入放大。所以SSD的调度需要考虑合并小写入,减少CPU计算调度。
1.1 调度算法介绍(基于Linux 5.10)
调度算法可以分为单队列(全局单一队列)和多队列(多CPU/硬件队列独立),因为现代主要使用多队列模式,所以我们主要介绍多队列的调度算法,先来看整体的调度结构:

整体多队列调度的初始化函数如下,后面到具体算法因其实现涉及代码比较多,我们会主要描述思路。
void elevator_init_mq(struct request_queue *q){ struct elevator_type *e; // 指向选中的I/O调度器类型结构体 int err; // 函数返回值,用于检查初始化是否成功 // 检查当前队列是否支持I/O调度器(如部分设备可能强制使用noop调度器) // 若不支持,则直接返回,不进行调度器初始化 if (!elv_support_iosched(q)) return; // 警告:若队列已注册(已完成初始化),则触发BUG_ON警告(仅调试用) // 确保调度器初始化仅在队列未注册时执行 WARN_ON_ONCE(blk_queue_registered(q)); // 若队列已关联调度器(非空),则无需重复初始化,直接返回 if (unlikely(q->elevator)) return; // 根据队列需求选择合适的I/O调度器 if (!q->required_elevator_features) { // 若队列无特殊功能需求,选择默认调度器(由内核配置或设备类型决定) e = elevator_get_default(q); } else { // 若队列有特殊功能需求(如支持层级调度、延迟控制等), // 则根据需求匹配具备对应功能的调度器 e = elevator_get_by_features(q); } // 若未找到合适的调度器(e为NULL),则退出初始化 if (!e) return; // 冻结队列:阻止新的I/O请求进入队列,确保初始化期间队列状态稳定 blk_mq_freeze_queue(q); // 暂停队列:等待队列中已有请求处理完成,避免初始化干扰正在进行的I/O blk_mq_quiesce_queue(q); // 初始化调度器:将选中的调度器(e)与队列(q)绑定,创建调度器上下文 // 该函数会为多队列的每个软件队列初始化调度器实例(如MQ-Deadline的每个队列私有数据) err = blk_mq_init_sched(q, e); // 恢复队列运行:允许队列重新接收并处理I/O请求 blk_mq_unquiesce_queue(q); // 解冻队列:完全恢复队列的正常操作 blk_mq_unfreeze_queue(q); // 检查调度器初始化是否失败 if (err) { // 打印警告信息,提示当前调度器初始化失败,将回退到"none"调度器(noop) pr_warn("\"%s\" elevator initialization failed, " "falling back to \"none\"\n", e->elevator_name); // 释放之前获取的调度器引用,避免资源泄漏 elevator_put(e); }}
1.1.1 BFQ调度
BFQ(Budget Fair Queueing)其含义为公平对待每个进程,其主要逻辑可以见下图,其中实线代表IO请求的方向,通过add方法添加到IO队列,然后使用调度器调度,由dispatch方法进行下发处理。
虚线箭头budget表示每个进程被分配的访问的最大扇区数目,其每访问一个扇区就会进行减少,一旦消耗完就会选择其他进程执行IO,当前用完的进程会被重新估算下一次的budget数量。
然后再来看Next active application selection,这是所有IO调度器的核心功能,本质就是选择出一个下一个有访问磁盘权力的队列,BFQ是从符合条件的队列中进行选择(如budget没用完的,等待时间较长的)。
图片
1.1.2 mq-deadLine调度
其整体逻辑如下:通过两个结构进行管理,一个用来记录磁盘位置排序(为了方便连续读取),一个按照时间排序(为了deadline优先),其为每个CPU配置一个队列,减少锁竞争,同时采用上述的双重排序策略来提高性能。
图片
1.1.3 kyber调度
其整体逻辑如下:在初始化阶段时创建四类请求队列(读、写、discard、other),初始化 Token 池(控制每种请求的最大并发数),并设置延迟目标(读请求优先低延迟,写请求平衡吞吐);应用请求先进入暂存队列,完成请求合并(减少 I/O 次数)和类型分类,再分别进入对应类型的分发队列;核心调度逻辑:
1)调度器按固定顺序轮询四类队列,避免某类请求长期被忽略;
2)通过Token 机制控制并发:每种请求需消耗 Token 才能被处理,Token 耗尽则队列挂起,直到请求完成释放 Token;
3)优先保障有 Token 的队列,避免无限制并发导致设备拥堵;
4)通过定期统计实际延迟来动态适应设备负载。
图片
1.1.4 总结比较
我们从调度器的优劣以及适用场景进行比较,同时会描述我们修改调度器的方式。
切换调度器方式如下,中间路径需要根据实际存储类型变化:
sudo echo kyber > /sys/block/hda/queue/scheduler
2.Page Cache
Page Cache是Linux用于缓存数据的核心机制,通过将磁盘数据暂存到内存中,减少磁盘IO次数,我们将从Page Cache的查看、缓存管理、读写交互以及页面回收四个部分进行介绍。
2.1 如何查看Page Cache
可以使用vmstat -n 1查看读写,其中主要信息就是cache字段,另外更为详细的信息可以使用cat/proc/meminfo查看,其部分内容如图:
图片
2.2 缓存管理
缓存管理主要的三个结构就是inode、page和address_space,其代表的含义和核心关联如下:
1)inode表示文件元数据,并通过i_mapping关联对应的address_space。
2)address_space是连接元数据inode和物理页page的核心,每个address_space对应一个打开的文件,根据index来找到对应页,并通过统一抽象的operations来适配不同文件系统。
3)page是物理页结构,描述实际数据信息。
图片
2.3 缓存交互
缓存交互可以分为读写操作,先来看读:
1)读操作,先检查缓存再实际读取,其流程图和交互图示如下:
图片
图片
2)写操作,先写缓存然后标记为脏页,异步回写,主要流程如下:
图片
2.4 缓存淘汰
缓存淘汰逻辑较为简单,使用的是LRU算法进行Page Cahce中页的淘汰。
3.总结
本文从两个角度来描述了IO高效的实现方式,一个是合理调度磁盘,一个是减少磁盘访问。了解了实现磁盘高效IO的思想,下一篇将会讲解特殊的优化,零拷贝技术。
相关攻略
第一步:彻底卸载旧版 Node js 为确保安装过程顺利,避免版本冲突,我们首先需要完全移除系统中可能存在的旧版本 Node js 及其关联组件。 请打开终端,依次执行以下命令: apt remove --purge -y nodejs libnode-dev npm 该命令将彻底卸载 Node j
为Nginx启用HTTPS加密,看似复杂实则核心步骤清晰。关键在于确保Nginx编译时已包含--with-http_ssl_module模块,并正确配置证书与私钥的绝对路径及严格权限(私钥文件权限应为600)。实现HTTPS服务的最小化配置仅需三行指令:listen 443 ssl、ssl_cert
Linux系统批量重命名文件有多种方法。基础方法是使用mv命令配合for循环,适合简单的前缀、后缀修改。C语言版rename命令可进行直接字符串替换。功能更强的Perl版rename支持正则表达式,能实现复杂模式匹配。mmv工具通过通配符映射,适合结构化重命名。无论使用哪种方法,都建议先通过预览模式确认操作,避免误改。
默认部署KubernetesDashboard后服务类型为ClusterIP,无法从外部访问。需将Service类型改为NodePort并指定30000-32767范围内的端口,才能通过浏览器直接访问。登录失败常因缺少权限绑定、token过期或命名空间错误。临时调试可使用port-forward,但生产环境不推荐。部署前需确保集群基础配置正确,避免后续问题。
配置Keepalived实现双机热备,一个常见的误解是认为软件装上就能自动实现高可用。实际上,真正的稳定运行,关键在于VRRP配置、健康检查绑定以及网络层对齐这三者必须严丝合缝。任何一个环节出错,比如virtual_router_id不一致,或者健康检查脚本失效,都可能导致虚拟IP(VIP)无法正常
热门专题
热门推荐
在现代化仓储物流管理中,实现实时、精准的库存可视化是提升运营韧性与效率的核心环节。近日,知名定制化第三方物流服务商Romark Logistics宣布了一项重要技术升级:在其位于哈兹尔顿的仓储基地正式部署由Dexory提供的AI驱动仓储可视化平台DexoryView。此举标志着Romark Logi
今天,谷歌正式将我们带入了一个新的阶段:AI智能体时代。其推出的Gemini Spark,被定义为一款能够全天候运行的个人AI助手。它的核心使命很明确——接管我们日益复杂的数字生活,并实实在在地替我们处理一些工作。 这款助手的“大脑”是最新发布的Gemini 3 5 Flash模型,而协调其行动的“
近日,《自然》杂志同期发表了两项突破性研究,展示了两种旨在革新科研工作流的AI系统。一款来自谷歌,名为Co-Scientist,强调人机深度协作;另一款由非营利机构FutureHouse开发,其系统更进一步,能对特定生物实验数据进行自动化评估与分析。 尽管谷歌表示其系统架构同样适用于物理学探索,但两
谷歌近期对其“氛围编程”平台进行了重要升级。现在,开发者可以直接在谷歌AI Studio中,通过自然语言对话来构建安卓原生应用。 具体操作流程非常直观:用户只需用日常语言描述自己的应用构思,平台内置的安卓模拟器便会实时生成应用预览。若想在实际设备上测试,只需将安卓手机连接至电脑,即可直接安装体验。更
今天,科大讯飞旗下孵化的AI硬件品牌未来智能,正式发布了其创新产品——viaim讯飞智能体耳机。这款产品的核心突破在于,将先进的办公AI Agent能力,集成到一款日常可佩戴的耳机设备中。它不仅超越了传统录音转写功能,更实现了长期记忆存储、多模型灵活调用与智能复盘分析,目标清晰:将耳机从单纯的音频播





