暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Linux系统有IO瓶颈?看看是不是它的问题!

恒生DBA公社 2021-04-21
779


写在前言

  

内核,作为Linux中极为复杂的部分,被广泛应用于各种计算机,包括嵌入式设备、手持设备、笔记本电脑、服务器、数据库服务器、视频服务器和体型巨大的超级计算机等场景,以上种种场景包含了许许多多不同的请求类型,这其中就包括对用户输入的响应(例如,流媒体音乐、视频或者其他交互性不能被中断的请求),并且要保证设备需要有良好的I/O性能,以确保数据能够被完整存储。因此内核需要通过调度器来满足这些请求,例如具有很高的I/O吞吐量的系统,就需要I/O调度器来对I/O进行管理。

调度器通过在内核中调度系统资源来实现低延迟的输入、更加流畅的交互请求、更快的I/O请求,或者以上这些需求的集合。而调度程序主要关注CPU资源,但也会兼顾其他系统资源(如,内存,输入设备,网络等)

而本文的重点就是介绍其中的I/O调度器和用于I/O调优的几种可选项。


在证券、期货和基金等金融客户的数据中心、O32、估值等数据库中,多次发生”log file sync”导致数据库性能下降的问题,系统服务发展部值班邮箱也收到不少客户现场发来的邮件,反馈以上问题,通过我们工程师排查处理发现,其中有一部分是由于logfile文件大小和组数配置不合理造成的,还有个别数据库LGWR trace文件有明显的警告信息,如下:


***  2018-06-28 14:04:37.080

Warning:  log write elapsed time 527ms, size 1756KB

Oracle官方MOS上提到一句话:“then the warning is most likelycaused by slow IO or OS resource starvation.“

那么I/O性能又和I/O调度器有什么关系呢,我们继续往下看



I/O调度器的概念

  

几乎所有在系统上运行的应用程序都会有I/O请求,就算是最普通的浏览网页也会向磁盘中写入一些小文件。想象一下,如果没有I/O调度器,那么每一个I/O请求都会向内核发送一个中断interrupt),并在数据块上移动磁头进行读写,以便完成自己的I/O操作。那么随着时间的推移,磁盘驱动器性能与系统的其他组件之间的差异将迅速增长,进而由于I/O阻塞,导致系统的性能下降。可想而知,当内核必须处理中断时,任何正在处理中的交互都会暂停,因此系统可能表现为无响应或缓慢。

那么如何来对I/O请求进行调度,让它们保持良好的交互性的,同时又确保良好的I/O性能?其实还是取决于工作量。比如,在某些情况下,可以在做其他事情的同时进行I/O处理,但是另外一种情况就需要尽快完成I/O,比如alter system checkpoint;为了平衡两种情况下的I/O负载,或者为了保证某种情况下的优先级,因此产生了I/O调度器。

知道了I/O调度器的产生之后,我们来了解一下Linux的I/O体系。

从上图可见Linux I/O调度器是Linux I/O体系的一个组件,它介于通用块层和块设备驱动程序之间。

Linux I/O调度器介于通用块层和块设备驱动程序之间,所以它接收来自通用块层的请求,试图合并请求,并找到最合适的请求下发到块设备驱动程序中。之后块设备驱动程序会调用一个函数来响应这个请求。

Linux整体I/O体系可以分为七层,它们分别是:

1.VFS虚拟文件系统:内核要跟多种文件系统打交道,内核抽象了这VFS,专门用来适配各种文件系统,并对外提供统一操作接口。

 

2.磁盘缓存:磁盘缓存是一种将磁盘上的一些数据保留着RAM中的软件机制,这使得对这部分数据的访问可以得到更快的响应。磁盘缓存在Linux中有三种类型:Dentry cache,Page cache,Buffer cache。

3. 映射层:内核从块设备上读取数据,这样内核就必须确定数据在物理设备上的位置,这由映射层(Mapping Layer)来完成。

 

4. 通用块层:由于绝大多数情况的I/O操作是跟块设备打交道,所以Linux在此提供了一个类似vfs层的块设备操作抽象层。下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准。

 

5. I/O调度层:大多数的块设备都是磁盘设备,所以有必要根据这类设备的特点以及应用特点来设置一些不同的调度器。

 

6. 块设备驱动:块设备驱动对外提供高级的设备操作接口。

 

7. 物理硬盘:这层就是具体的物理设备。

那么,在如此复杂的I/O体系以及千变万化的I/O需求下,I/O调度器将扮演哪些角色呢?



I/O调度器的类型

  

Linux 从2.4内核开始支持I/O调度器,到目前为止有5种类型:Linux 2.4内核的Linus Elevator、Linux 2.6内核的Deadline、 Anticipatory、 CFQ、 Noop,其中Anticipatory从Linux 2.6.33版本后被删除了。目前主流的Linux发行版本使用Deadline、 CFQ、 Noop三种I/O调度器。下面依次简单介绍:


2.1.Linus Elevator

在2.4 内核中它是第一种I/O调度器。它的主要作用是为每个设备维护一个查询请求,当内核收到一个新请求时,如果能合并就合并。如果不能合并,就会尝试排序。如果既不能合并,也没有合适的位置插入,就放到请求队列的最后。


2.2.Anticipatory

Anticipatory的中文含义是"预料的,预想的",顾名思义有I/O发生时,如果又有进程请求I/O操作,则将产生一个默认的6毫秒猜测时间,猜测下一个进程请求I/O是要干什么的。这个I/O调度器对读操作优化服务时间,在提供一个I/O的时候进行短时间等待,使进程能够提交到另外的I/O。Anticipatory算法从Linux2.6.33版本后被删除了,因为使用CFQ通过配置也能达到Anticipatory的效果。


2.3.DeadLine

Deadline翻译成中文是截止时间调度器,是对Linus Elevator的一种改进,它避免有些请求太长时间不能被处理。另外可以区分对待读操作和写操作。DEADLINE额外分别为读I/O和写I/O提供了FIFO队列。


2.4. CFQ

CFQ全称Completely Fair Scheduler ,中文名称完全公平调度器,它是现在许多 Linux 发行版的默认调度器,CFQ是内核默认选择的I/O调度器。它将由进程提交的同步请求放到多个进程队列中,然后为每个队列分配时间片以访问磁盘。对于通用的服务器是最好的选择,CFQ均匀地分布对I/O带宽的访问。CFQ为每个进程和线程,单独创建一个队列来管理该进程所产生的请求,以此来保证每个进程都能被很好的分配到I/O带宽,I/O调度器每次执行一个进程的4次请求。该算法的特点是按照I/O请求的地址进行排序,而不是按照先来后到的顺序来进行响应。简单来说就是给所有同步进程分配时间片,然后才排队访问磁盘。


2.5. NOOP

NOOP全称No Operation,中文名称电梯式调度器,该算法实现了最简单的FIFO队列,所有I/O请求大致按照先来后到的顺序进行操作。NOOP实现了一个简单的FIFO队列,它像电梯的工作方式一样对I/O请求进行组织。它是基于先入先出(FIFO)队列概念的 Linux 内核里最简单的I/O 调度器。此调度程序最适合于固态硬盘。



I/O调度器的选择

  

目前主流Linux发行版本使用三种I/O调度器:DeadLine、CFQ、NOOP,通常来说Deadline适用于大多数环境,特别是写入较多的文件服务器,从原理上看,DeadLine是一种以提高机械硬盘吞吐量为思考出发点的调度算法,尽量保证在有I/O请求达到最终期限的时候进行调度,非常适合业务比较单一并且I/O压力比较重的业务,比如Web服务器,数据库应用等。CFQ为所有进程分配等量的带宽,适用于有大量进程的多用户系统,CFQ是一种比较通用的调度算法,它是一种以进程为出发点考虑的调度算法,保证大家尽量公平,为所有进程分配等量的带宽,适合于桌面多任务及多媒体应用。NOOP 对于闪存设备和嵌入式系统是最好的选择。对于固态硬盘来说使用NOOP是最好的,DeadLine次之,而CFQ效率最低。



查看linux系统的I/O调度器

 

查看Linux系统的I/O调度器一般分成两个部分,一个是查看Linux系统整体使用的I/O调度器,另一个是查看某磁盘使用的I/O调度器。

 

4.1.查看当前系统支持的I/O调度器

 

[root@lamajay1  home]# dmesg | grep -i scheduler

[    0.775046] io scheduler noop registered

[    0.775050] io scheduler deadline  registered (default)

[    0.775073] io scheduler cfq registered

[    0.775076] io scheduler mq-deadline registered

[    0.775079] io scheduler kyber registered

上面的输出显式,deadline是系统中默认的I/O调度器。


4.2. 查看某块硬盘的IO调度算法I/O调度器

[root@lamajay1 home]# cat  /sys/block/sda/queue/scheduler

noop [deadline] cfq

上面的输出显式,deadline是sda磁盘当前使用的调度器。



修改linux系统的I/O调度器

  

修改Linux系统的 I/O调度器有三种方法,分别是使用shell命令、使用grubby命令或者修改grub配置文件。下面依次介绍:


.5.1. 使用shell临时修改

Linux下更改的I/O调度器很简单。不需要更新内核,可以使用shell命令修改:

[root@lamajay1  home]# echo noop > sys/block/sda/queue/scheduler

[root@lamajay1  home]# cat sys/block/sda/queue/scheduler

[noop]  deadline cfq

上面的命令把noop设置为一个磁盘的I/O调度器,你可以随时更改而无需重启。


.5.2. 永久修改默认的I/O调度器

使用shell命令修改I/O调度器,只是临时修改,系统重启后,修改的调度器就会失效,要想修改默认的调度器,有两种方法使用grubby命令或者直接编辑grub配置文件。


5.2.1.使用grubby命令(已在Linux6.5中测试)

例如需要把I/O调度器从cfq调整成 DeadLine ,命令如下:

[root@rac1  rules.d]# grubby --grub --update-kernel=ALL --args="elevator=cfq"

通过设置内核加载参数, 这样当机器重启的时候,系统自动把所有设备的 I/O调度器变成cfq.


5.2.2.使用vi编辑器修改配置文件(已在Linux7.5中测试)

[root@lamajay1  ~]# vi etc/default/grub

GRUB_CMDLINE_LINUX="rd.lvm.lv=rhel/root  rd.lvm.lv=rhel/swap rhgb quiet transparent_hugepage=never elevator=deadline"

[root@lamajay1  ~]# grub2-mkconfig -o boot/grub2/grub.cfg

重启系统即可。



I/O调度器的测试

  

6.1.测试磁盘读写

[root@lamajay1  ~]# echo noop > /sys/block/sda/queue/scheduler

[root@lamajay1  ~]# time dd if=/dev/sda1 of=/tmp/test bs=2M count=300 conv=fdatasync

100+0  records in

100+0  records out

209715200  bytes (210 MB) copied, 3.38164s, 62.1 MB/s

 

real 0m3.435s

user      0m0.000s

sys 0m0.219s

 

[root@lamajay1  ~]# echo cfq > /sys/block/sda/queue/scheduler

[root@lamajay1  ~]# time dd if=/dev/sda1 of=/tmp/test bs=2M count=300 conv=fdatasync

100+0  records in

100+0  records out

209715200  bytes (210 MB) copied, 3.34928s, 62.7 MB/s

real 0m3.383s

user      0m0.001s

sys 0m0.213s

 

[root@lamajay1  ~]# echo deadline > /sys/block/sda/queue/scheduler

[root@lamajay1  ~]# time dd if=/dev/sda1 of=/tmp/test bs=2M count=300 conv=fdatasync

100+0  records in

100+0  records out

209715200  bytes (210 MB) copied, 3.06569s, 68.5 MB/s

 

real 0m3.168s

user      0m0.000s

sys 0m0.269s

结果:

       第一,deadline: 用时3.06569s,速度68.5 MB/s

       第二,cfq:用时3.34928s, 速度62.7 MB/s

       第三,noop:用时3.3



总结

  

Linux I/O调度器是 Linux 内核中的一个组成部分,用户可以通过根据不同的存储器来设置 Linux I/O 调度器从而达到优化系统性能。 一般来说 NOOP 调度器最适合于固态硬盘,DeadLine 调度器适用于写入较多的文件服务器,比如Web服务器,数据库应用等,而CFQ 调度器适合于桌面多任务及媒体应用。

 

注①:简单理解即,在内核处理程序A的I/O请求时,突然插入了程序B,程序B就可以理解为一个中断。在linux kernel中也提供中断机制,用于处理上述突发事件。


文章转载自恒生DBA公社,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论