一文搞懂 | Linux 内核的 4 大 IO 调度算法

点击蓝字

00033a0f9690e5fa3e40947fc468ca3a.png

关注我们

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

来源于网络,侵删

Linux 内核包含4个IO调度器:

  • Noop IO scheduler

  • Anticipatory IO scheduler

  • Deadline IO scheduler 

  • CFQ IO scheduler

anticipatory, 预期的;提早发生的;期待着的

通常磁盘的读写影响是由磁头到柱面移动造成了延迟,解决这种延迟内核主要采用两种策略:缓存和IO调度算法来进行弥补。

本文做一简单介绍。

调度算法概念

  1. 当向设备写入数据块或是从设备读出数据块时,请求都被安置在一个队列中等待完成。

  2. 每个块设备都有它自己的队列。

  3. I/O调度程序负责维护这些队列的顺序,以更有效地利用介质.I/O调度程序将无序的I/O操作变为有序的I/O操作。

  4. 内核必须首先确定队列中一共有多少个请求,然后才开始进行调度。

d106ee8f4762eed0bbf5a0ac79c3dbed.png

IO 调度器(IO Scheduler)

7d87a3f5925ad189829ead686de798f0.png

IO调度器(IO Scheduler)是操作系统用来决定块设备上IO操作提交顺序的方法。存在的目的有两个,一是提高IO吞吐量,二是降低IO响应时间。然而IO吞吐量和IO响应时间往往是矛盾的,为了尽量平衡这两者,IO调度器提供了多种调度算法来适应不同的IO请求场景。其中,对数据库这种随机读写的场景最有利的算法是DEANLINE。

IO调度器在内核栈中所处位置如下:

45462a338aa36cca8cc00f3b8412987d.png

849e7d06fdb81f054b0c7e24bba83a37.png

块设备最悲剧的地方就是磁盘转动,这个过程会很耗时间。

每个块设备或者块设备的分区,都对应有自身的请求队列(request_queue),而每个请求队列都可以选择一个I/O调度器来协调所递交的request。I/O调度器的基本目的是将请求按照它们对应在块设备上的扇区号进行排列,以减少磁头的移动,提高效率。每个设备的请求队列里的请求将按顺序被响应。实际上,除了这个队列,每个调度器自身都维护有不同数量的队列,用来对递交上来的request进行处理,而排在队列最前面的request将适时被移动到请求队列中等待响应。

22c00f62a435ed1387ad25c15de22577.png

IO scheduler 的作用主要是为了减少磁盘转动的需求。主要通过2种方式实现:

      1. 合并

      2. 排序

每个设备都会自己对应请求队列,所有的请求在被处理之前都会在请求队列上。在新来一个请求的时候如果发现这个请求和前面的某个请求请求的位置是相邻的,那么就可以合并为一个请求。如果不能找到合并的,就会按照磁盘的转动方向进行排序。通常IO scheduler 的作用就是为了在进行合并和排序的同时,也不会太影响单个请求的处理时间。

1、NOOP

2eb3065359a9346ef5467843564a37f6.png

FIFO

1. noop是什么? noop是一种输入输出调度算法。NOOP, No Operation. 什么都不做,请求来一个处理一个。这种方式实施起来简单,也更有效。问题就是disk seek 太多,对于传统磁盘,这是不能接受的。但对于SSD 磁盘就可以,因为SSD 磁盘不需要转动。

2. noop的别称 又称为电梯调度算法。

3. noop原理是怎样的?

将输入输出请求放到一个FIFO队列中,然后按次序执行队列中的输入输出请求:当来一个新请求时:

1. 如果能合并就合并;

2. 如果不能合并,就会尝试排序。如果队列上的请求都已经很老了,这个新的请求就不能插队,只能放到最后面。否则就插到合适的位置;

3. 如果既不能合并,又没有合适的位置插入,就放到请求队列的最后;

4. 适用场景

4.1 在不希望修改输入输出请求先后顺序的场景下;

4.2 在输入输出之下具有更加智能调度算法的设备,如NAS存储设备;

4.3 上层应用程序已经精心优化过的输入输出请求;

4.4 非旋转磁头式的磁盘设备,如SSD磁盘

2、CFQ(Completely Fair Queuing, 完全公平排队)

CFQ(Completely Fair Queuing)算法,顾名思义,绝对公平算法。它试图为竞争块设备使用权的所有进程分配一个请求队列和一个时间片,在调度器分配给进程的时间片内,进程可以将其读写请求发送给底层块设备,当进程的时间片消耗完,进程的请求队列将被挂起,等待调度。

每个进程的时间片和每个进程的队列长度取决于进程的IO优先级,每个进程都会有一个IO优先级,CFQ调度器将会将其作为考虑的因素之一,来确定该进程的请求队列何时可以获取块设备的使用权。

IO优先级从高到低可以分为三大类:

RT(real time)

BE(best try)

IDLE(idle)

其中RT和BE又可以再划分为8个子优先级。可以通过ionice 去查看和修改。优先级越高,被处理得越早,用于这个进程的时间片也越多,一次处理的请求数也会越多。

实际上,我们已经知道CFQ调度器的公平是针对于进程而言的,而只有同步请求(read或syn write)才是针对进程而存在的,他们会放入进程自身的请求队列,而所有同优先级的异步请求,无论来自于哪个进程,都会被放入公共的队列,异步请求的队列总共有8(RT)+8(BE)+1(IDLE)=17个。

从Linux 2.6.18起,CFQ作为默认的IO调度算法。对于通用的服务器来说,CFQ是较好的选择。具体使用哪种调度算法还是要根据具体的业务场景去做足benchmark来选择,不能仅靠别人的文字来决定。

3、DEADLINE

DEADLINE在CFQ的基础上,解决了IO请求饿死的极端情况。

除了CFQ本身具有的IO排序队列之外,DEADLINE额外分别为读IO和写IO提供了FIFO队列。

adf48f3d1548273ae08b7bec22459f86.png

读FIFO队列的最大等待时间为500ms,写FIFO队列的最大等待时间为5s(当然这些参数都是可以手动设置的)。

FIFO队列内的IO请求优先级要比CFQ队列中的高,而读FIFO队列的优先级又比写FIFO队列的优先级高。优先级可以表示如下:

FIFO(Read) > FIFO(Write) > CFQ

deadline 算法保证对于既定的 IO 请求以最小的延迟时间,从这一点理解,对于 DSS 应用应该会是很适合的。

deadline 实际上是对Elevator 的一种改进: 

1. 避免有些请求太长时间不能被处理。

2. 区分对待读操作和写操作。

deadline IO 维护3个队列。第一个队列和Elevator 一样, 尽量按照物理位置排序。第二个队列和第三个队列都是按照时间排序,不同的是一个是读操作一个是写操作。

deadline IO 之所以区分读和写是因为设计者认为如果应用程序发了一个读请求,一般就会阻塞到那里,一直等到的结果返回。而写请求则不是通常是应用请求写到内存即可,由后台进程再写回磁盘。应用程序一般不等写完成就继续往下走。所以读请求应该比写请求有更高的优先级。

在这种设计下,每个新增请求都会先放到第一个队列,算法和Elevator的方式一样,同时也会增加到读或者写队列的尾端。这样首先处理一些第一队列的请求,同时检测第二/三队列前几个请求是否等了太长时间,如果已经超过一个阀值,就会去处理一下。这个阀值对于读请求时 5ms, 对于写请求时5s。

个人认为对于记录数据库变更日志的分区,例如oracle 的online log, mysql 的binlog 等等,最好不要使用这种分区。因为这类写请求通常是调用fsync 的。如果写完不成,也会很影响应用性能的。

4、ANTICIPATORY

CFQ和DEADLINE考虑的焦点在于满足零散IO请求上。对于连续的IO请求,比如顺序读,并没有做优化。

为了满足随机IO和顺序IO混合的场景,Linux还支持ANTICIPATORY调度算法。ANTICIPATORY的在DEADLINE的基础上,为每个读IO都设置了6ms的等待时间窗口。如果在这6ms内OS收到了相邻位置的读IO请求,就可以立即满足。

小结

IO调度器算法的选择,既取决于硬件特征,也取决于应用场景。

在传统的SAS盘上,CFQ、DEADLINE、ANTICIPATORY都是不错的选择;对于专属的数据库服务器,DEADLINE的吞吐量和响应时间都表现良好。

然而在新兴的固态硬盘比如SSD、Fusion IO上,最简单的NOOP反而可能是最好的算法,因为其他三个算法的优化是基于缩短寻道时间的,而固态硬盘没有所谓的寻道时间且IO响应时间非常短。

3d0ab7724f1e7dd811c1adf6ad9d5300.jpeg

如果你年满18周岁以上,又觉得学【C语言】太难?想尝试其他编程语言,那么我推荐你学Python,现有价值499元Python零基础课程限时免费领取,限10个名额!
▲扫描二维码-免费领取

戳“阅读原文”我们一起进步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337107.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

众神进入瓦尔哈拉_一时冲动:“通往瓦尔哈拉之路的冒险”

众神进入瓦尔哈拉通过所有有关Java 9和Project Jigsaw的讨论,我们不应忽视Java的另一重大变化。 希望在第10版或第11版中, Valhalla项目能够实现并介绍价值类型和专业化。 那么,这是什么一回事,项目进展如何,面临什么…

当电子工程师十余年,感慨万千!

点击蓝字关注我们因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络,侵删当电子工程师也一些年头了,不算有出息,环顾四周,也没有看见几个有出息的。回顾工程师生涯,感慨万…

canva画图 图片居中裁剪_css实现不定宽高的图片img居中裁剪_类似微信朋友圈图片效果...

需求如下:前端需要显示矩形的缩略图,接口返回的图片尺寸大小不一,宽高不相等,需要前端来处理并显示成正方形,类似微信朋友圈图片的效果,等比例正方形显示在列表中,让图片根据宽高来自适应显示在…

哈希策略_优化哈希策略的简介

哈希策略总览 用于哈希键的策略可以直接影响哈希集合(例如HashMap或HashSet)的性能。 内置的哈希函数被设计为通用的,并且可以在各种用例中很好地工作。 我们可以做得更好,特别是如果您对用例有一个很好的了解吗? 测…

面试大全 | C语言高级部分总结,2.6万字长文

点击蓝字关注我们因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络,侵删一、内存大话题1.0、内存就是程序的立足之地,体现内存重要性。1.1、内存理解:内存物理看是有很多个 Bank(就是…

c#设计12星座速配软件_C#设计模式(12)——组合模式

阅读目录1.组合模式在软件开发中我们经常会遇到处理部分与整体的情况,如我们经常见到的树形菜单,一个菜单项的子节点可以指向具体的内容,也可以是子菜单。类似的情况还有文件夹,文件夹的下级可以是文件夹也可以是文件。举一个例子…

hibernate与jpa_将JPA Hibernate与OptaPlanner集成

hibernate与jpa我们一直在改进OptaPlanner与JEE其余部分的集成,因此更容易构建可以正常工作的最终用户应用程序。 让我们看一下改进的JPA Hibernate集成。 基础 JPA Hibernate和OptaPlanner都可以在POJO(普通的旧Java对象)上工作&#xff0c…

程序如何运行,编译、链接、装入?

点击蓝字关注我们因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络,侵删一、地址概念和程序如何运行在多道程序环境下,要使程序运行,必须先为之创建进程。而创建进程的第一件事,便是…

python举两种字符串引号的例子_python里的单引号和双引号的有什么作用

在Python当中表达字符串既可以使用单引号,也可以使用双引号,那两者有什么区别吗?python单引号和双引号的区别简单来说,在Python中使用单引号或双引号是没有区别的,都可以用来表示一个字符串。但是这两种通用的表达方式…

枚举对象注释_如何以及何时使用枚举和注释

枚举对象注释本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的旅程! 在这里查看 !…

background 互联网图片_cssbackground-image和layer-background-image的区别

layer-background-image语法:layer-background-image : none | url (url)参数:none :  无背景图url :  使用绝对或相对地址指定背景图像说明:设置或检索对象整个区域的背景图像。示例:code {position: absolute;top: 100px; lef…

纪事本 乱码_纪事日记–可自定义的数据存储

纪事本 乱码总览 使任何数据结构或算法尽可能快的方法是使代码完全执行您想要的操作,而无需执行其他操作。 建立一个可以做任何人想做的每件事的数据存储的问题是,它做得特别不好。 自定义数据存储在性能方面可以实现什么? 您可以支持&#…

datavideo切换台说明书_【新品发布】datavideo SE-650 高清四通道切换台

还在为音乐演唱会的拍摄而烦恼吗?或者为体育比赛的多机位发愁?或者为微课、优课、慕课制作而焦头烂额?大部分用户对多机位的恐惧来源于相关产品令人发指的复杂和专业性,面对满眼的键盘会有无从下手之感,很多学校和工作…

NSA:建议从 C/C++ 切换到内存安全语言

点击蓝字关注我们因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络,侵删美国国家安全局(NSA)发布了一份指南,旨在帮助软件开发商和运营商预防和缓解软件内存安全问题。其鼓励组织将编…

探索cqrs和事件源_编写基于事件的CQRS读取模型

探索cqrs和事件源关于事件源和CQRS的讨论似乎通常集中在CQRS上下文中的整体系统架构或领域驱动设计的各种形式。 但是,尽管也有一些有趣的考虑,但读取模型经常被忽略。 在本文中,我们将介绍通过使用事件流来填充视图模型的示例实现。 总览 …

shmmax单位_kernel.shmmax ,kernel.shmmni 和kernel.shmall

kernel.shmmax 2147483648//该参数定义了共享内存段的最大尺寸(以字节为单位)。其值应>sag_max_size初始化参数的大小,否则SAG由多个内存段构成,效率降低,还要不小于物理内存的一半,默认情况下在32位x86系统中,OracleSGA最大不能超过1.7GB.缺省为32M,对于oracle…

C# 11正式发布

点击蓝字关注我们因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络,侵删C# 11 现已发布。公告称,“随着每个版本的发布,社区的参与度越来越高,贡献了从建议、见解和错误报告到整个功…

java 自定义运算符_Java中集合的自定义运算符

java 自定义运算符总览 操作员重载有多种语言可用。 Java对String类型的运算符的支持对运算符的重载非常有限。 我们可以利用其他语言支持运算符的不同方式,但是我们可以在Java中实现一个使用Java已经使用的约定的实现。 获取,设置和放置操作 集合的运…

marker主题 ros_(五)ROS主题理解

参考网址:1,小海龟例子(1) 在新的终端打开roscore$ roscore---如果出错,请确定关闭所有ROS命令或者路径,重试。(2) 在新的终端打开运行小海龟界面$ rosrun turtlesimturtlesim_node得到结果&…

分享一个通用的嵌入式驱动层

点击蓝字关注我们因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络,侵删C 语言面向对象编程的最佳实践一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会…