《Linux 性能及调优指南》1.4 硬盘I/O子系统

时间:2021-12-30 15:06:42
翻译:飞哥 (http://hi.baidu.com/imlidapeng)

版权所有,尊重他人劳动成果,转载时请注明作者和原始出处及本声明。

原文名称:《Linux Performance and Tuning Guidelines》

原文地址:http://www.redbooks.ibm.com/abstracts/redp4285.html

-------------------------------------------------------------------------------------------

1.4.1 I/O子系统架构
1.4.2 缓存
1.4.3 块层
1.4.4 I/O设备驱动
1.4.5 RAID及存储系统

-------------------------------------------------------------------------------------------

​在处理器解码和执行指令前,先从扇区中读取数据并将数据置于处理器的缓存和寄存器中。执行结果会被写回硬盘。

下面我们将简单地介绍一下Linux硬盘I/O子系统,来更好的认识这个可以对系统性能产生很大影响的组件。

​1.4.1 I/O子系统架构

图1-18展示了I/O子系统架构的基本概念。

《Linux 性能及调优指南》1.4 硬盘I/O子系统
图1-18 I/O子系统架构

为了能快速的对I/O子系统运作有一个整体的认识,我们将举一个写数据到硬盘的例子。
​下面的步骤概述了当一个硬盘写操作执行时的基本操作。
​假设存储于硬盘片扇区上的数据已经被读取到分页缓存中。

​1.进程使用write()系统调用发出写文件的请求。

2.内核更新映射此文件的分页缓存。

3.pdflush内核线程将分页缓存清空至硬盘。

4.文件系统层将多个块缓冲【block buffer】置于bio结构中(参见1.4.3,“块层”)并提交一个写请求给块设备层。

5.块设备层从上一层收到请求,执行一个I/O elevator操作并发出进入I/O请求队列的请求。

6.设备驱动如SCSI或其它设备的特定驱动来负责完成写操作。

7.硬盘设备韧体负责执行硬件操作像确定磁头、旋转和传输数据至磁盘片上的扇区。

​1.4.2 缓存

在过去的20年里,处理器性能的提升已超过计算机中其它元件如处理器缓存、总线、RAM、硬盘等。
​内存和硬盘较慢的访问速度限制了系统的整体性能,所以单单提高处理器速度并不能让系统性能提升。
​缓存机制通过将常用数据缓存至快速内存中来解决此问题。它减少了访问较慢内存的机会。
​目前计算机系统中几乎所有的I/O元件都是用了这项技术如硬盘驱动器缓存、硬盘控制器缓存、文件系统缓存、各种应用程序的缓存等等。

​内存层级【Memory Hierarchy】

图1-19展示了内存层级的概念。
​CPU寄存器和硬盘在访问速度上有着很大的差距,CPU需要花费更多的时间等待从缓慢硬盘上获取数据,这显然降低了一个快速CPU所带了的好处。
​内存层级结构通过在CPU和硬盘间部署一级缓存、二级缓存、RAM和其他一些缓存可以减少这种速度上的失衡。
​它能减少处理器访问较慢内存和硬盘的机会。靠近处理器的内存拥有更快的访问速度但容量却较小。

这种技术也可以利用局部性引用原则。快速内存中更高的缓存命中率就意味着更高的数据访问速度。

《Linux 性能及调优指南》1.4 硬盘I/O子系统
图1-19 内存层级

局部性引用【Locality of Reference】

正如我们前面在“内存层级”中所述,取得更高的缓存命中率是性能提升的关键。
​为取得更高的缓存命中率,“局部性引用”技术被使用。这项技术是基于下面的原则:

▶ 最近使用过的数据非常有可能在近期被再次使用(时间局部性)

▶ 位于使用过数据相邻的数据非常有可能被使用(空间局部性)

​图1-20说明了这个原则。

《Linux 性能及调优指南》1.4 硬盘I/O子系统
图1-20局部性引用

​这个原则被应用于Linux的许多元件中如分页缓存、文件对象缓存(i-node缓存、目录项缓存等)、预读缓冲以及更多。

​清空脏缓冲【Flushing a dirty buffer】

当进程从硬盘中读取数据时,数据被复制到内存。
​此进程和其他进程都可以从缓存在内存中的副本取得相同数据。当有进程尝试变更数据,会先更改内存中数据。
​此时,硬盘中数据和内存中数据发生不一致,内存中数据被称为脏缓冲。
​赃缓冲会被尽快同步至硬盘,但如果系统突然崩溃内存中数据就会丢失。

同步脏数据的进程叫做flush。

​在Linux2.6内核中,pdflush内核线程负责清空数据到硬盘。
​此操作会定期(kupdate)执行或者当内存中脏缓冲比例超过临界值(bdflush)时执行。
​此临界值配置在/proc/sys/vm/dirty_background_ratio文件中。
​更多信息参见4.5.1“设置内核交换和pdflush行为”。

《Linux 性能及调优指南》1.4 硬盘I/O子系统
图1-21清空脏数据

​1.4.3 块层
块层负责管理所有关于块设备操作的相关活动(参见图1-18)。
​块层中的关键数据结构就是bio,bio结构是位于文件系统层和块层之间的一个接口。

当执行写操作时,文件系统层尝试向由块缓冲组成的分页缓存中写入。
​将连续的块组成一个bio结构,然后将bio传送至块层。(参见图1-18)

块层获得bio请求并将其链接至I/O请求队列(I/O Request Queue)中。
​​这个链接操作叫做I/O调度器【原文中使用的单词为elevator】。

​​在Linux 2.6内核中,共有四种I/O调度器算法可以选择,他们是:

块的大小【Block Sizes】

块大小(读写硬盘数据的最小数量)能直接影响服务器的性能。
​一个指导性方案是,如果你的服务器处理非常多的小文件,较小的块大小会更有效率。
​如果你的服务器用于处理大文件,较大的块大小可以提升性能。
​已有的文件系统是不能更改块大小的,只有在重新格式化时才能修改当前块大小。

​I/O调度器

Linux 2.6内核的I/O调度器使用了新模式,而Linux 2.4内核中采用的是一种简单、通用的I/O调度器,而在2.6内核中有四种调度器可供选择。
​因为Linux被用来执行各种各样的任务,对I/O设备和负载要求有显著的不同,一台笔记本电脑和一台有10000个用户的数据库对I/O的需求就有很大差别。

​​为满足这样的需求,Linux提供了四种I/O调度器。

▶ Anticipatory

Anticipatory I/O 调度器是基于假设块设备只有一个物理寻址磁头(例如一个单SATA驱动)。
​Anticipatory 调度器使用了增加预测启发能力的Deadline机制(下面会详细介绍)。
​正像名字所暗示的,Anticipatory I/O Anticipatory会“猜测”I/O并尝试使用单一较大的数据流写入硬盘代替多个小的随机硬盘访问。
​这种预测启发能力会造成写入的延迟,但它可以提高一般用途系统如个人电脑的写入吞吐量。
​在2.6.18内核中Anticipatory 调度器被作为标准的I/O调度器,然而大多数企业发行版默认使用CFQ 调度器。

​▶ 完全公平队列(CFQ)

CFQ elevator通过为每个进程都维护单独的I/O队列来实现QoS(服务质量)策略。
​CFQ调度器也适用于拥有许多互相竞争进程的多用户系统。它可以避免进程饿死并降低延迟。
​自从2.6.18内核,CFQ调度器已被作为默认的I/O调度器。

​依据系统设置和负载情况,CFQ调度器可以降低单一主应用程序的速度,例如使用其公平向导算法的大型数据库 。
​默认配置进程组确保公平,进程组与其它进程竞争。
​例如数据库所有写分页缓存(所有pdflush实例为一个群组)的操作被认为是一个应用程序与其它后台进程竞争。
​在这样的情况下它对于测试I/O调度器配置或Deadline调度器也是非常有用的。

​▶ Deadline

Deadline是个使用最后期限算法的轮询调度器(Round Robin),它提供I/O子系统接近实时的操作。
​Deadline在维持满意的硬盘吞吐量的同时可以提供优秀的请求延迟。Deadline的算法能确保不会有进程被饿死。

​▶ NOOP

NOOP代表不操作【No Operation】,名字就说明了其主要功能。
​NOOP简单且直接,它只实现一个简单的FIFO队列并不对任何数据排序。
​NOOP只是简单地合并数据请求,因此它增加非常低的处理器负载。
​NOOP假设块设备拥有自己的调度器算法如SCSI的TCQ或没有寻道的延迟的块设备如闪存卡。

​注释:在2.6.18内核中可以为每个硬盘子系统设定特定的I/O调度器,不需要在系统级上设定。

​1.4.4 I/O设备驱动

Linux内核使用设备的驱动程序来控制设备。设备的驱动程序通常为独立的内核模组,它让操作系统中的每个设备都可以使用。
​当设备驱动被加载后,它就作为内核的一部分运行并完全控制设备。

​​这里我们将介绍一下SCSI设备驱动。

SCSI

小型计算机系统接口(SCSI)是一种最常用的I/O设备技术,特别是在企业服务器环境中。
​在Linux内核的实现中,SCSI设备由设备驱动模组控制。它们由下面几种模组构成。

▶ 上层驱动:sd_mod,sr_mod(SCSI-CDROM),st(SCSI Tape),sq(SCSI generic device)等。
提供支持几种SCSI设备的功能如SCSI-CDROM,SCSI磁带等。

▶ 中间层驱动:scsi_mod
实现SCSI协议和SCSI共有的功能。

▶ 底层驱动
提供设备的底层访问。底层驱动为每个设备提供特定的硬件驱动。
​例如用于IBM ServeRAID控制器的ips、用于Qlogic HBA的qla2300、用于LSI Logic SCSI控制器的mptscsih等。

▶ 伪驱动:ide-scsi
用于模拟IDE-SCSI。

《Linux 性能及调优指南》1.4 硬盘I/O子系统
图1-22 SCSI驱动结构

​如果要设备实现特殊的功能,它需要在设备韧体和底层设备驱动中实现。
​支持什么功能取决于你使用什么设备和设备驱动的版本。设备自己也可以支持所希望的功能。
​通过设定设备驱动参数可以调整特定的功能。你可以调整/etc/modules.conf测试某些性能。关于使用方法和技巧请参见设备和驱动相关文档。

​1.4.5 RAID和存储系统

就系统效能而言存储系统的选择配置与RAID类型也是重要因素。
​Linux支持软RAID,但此主题的详细内容已超出本文范畴,我将在4.6.1“安装Linux前硬件的选择”中介绍一些调优相关的内容。