来自 美高梅4858永利777 2020-04-18 03:30 的文章
当前位置: 美高梅游戏平台网站 > 美高梅4858永利777 > 正文

Linux 性能优化之 IO 子系统

本文介绍了对 Linux IO 子系统性能进行优化时需要考虑的因素,以及一些 IO 性能检测工具。

文件系统优化

** 动态调整请求队列数来提高效率,默认请求队列数为:128, 可配置512 **
[root@c37 queue]# cat /sys/block/sda/queue/nr_requests
128
** read_ahead, 通过数据预读并且记载到随机访问内存方式提高磁盘读操作,默认值 128,ceph配置:8192 **
[root@c37 queue]# cat /sys/block/sda/queue/read_ahead_kb
128
** 关闭最后一次访问文件(目录)的时间戳 **
例如:
mount -t xfs -o defaults,noatime,nodiratime /dev/sda5 /data
** 大文件,大容量,大量文件数建议使用xfs文件系统 **

本文的大部分内容来自 IBM Redbook - Linux Performance and Tuning Guidelines

调整I/O调度算法

[root@c37 queue]# cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]
centos6.x默认为cfq
调整为deadline
[root@c37 queue]# echo deadline > /sys/block/sda/queue/scheduler
[root@c37 queue]# cat /sys/block/sda/queue/scheduler
noop anticipatory [deadline] cfq
** I/O调度算法介绍 **

  1. CFQ(完全公平排队I/O调度程序) 默认
    特点:
    CFQ试图均匀地分布对I/O带宽的访问,避免进程被饿死并实现较低的延迟,是deadline和as调度器的折中.
    CFQ赋予I/O请求一个优先级,而I/O优先级请求独立于进程优先级,高优先级的进程的读写不能自动地继承高的I/O优先级.
    工作原理:
    CFQ为每个进程/线程,单独创建一个队列来管理该进程所产生的请求,也就是说每个进程一个队列,各队列之间的调度使用时间片来调度,
    以此来保证每个进程都能被很好的分配到I/O带宽.I/O调度器每次执行一个进程的4次请求.
  2. NOOP(电梯式调度程序)
    特点:
    在Linux2.4或更早的版本的调度程序,那时只有这一种I/O调度算法.
    NOOP实现了一个简单的FIFO队列,它像电梯的工作主法一样对I/O请求进行组织,当有一个新的请求到来时,它将请求合并到最近的请求之后,以此来保证请求同一介质.
    NOOP倾向饿死读而利于写.
    NOOP对于闪存设备,RAM,嵌入式系统是最好的选择.
    电梯算法饿死读请求的解释:
    因为写请求比读请求更容易.
    写请求通过文件系统cache,不需要等一次写完成,就可以开始下一次写操作,写请求通过合并,堆积到I/O队列中.
    读请求需要等到它前面所有的读操作完成,才能进行下一次读操作.在读操作之间有几毫秒时间,而写请求在这之间就到来,饿死了后面的读请求.
  3. Deadline(截止时间调度程序)
    特点:
    通过时间以及硬盘区域进行分类,这个分类和合并要求类似于noop的调度程序.
    Deadline确保了在一个截止时间内服务请求,这个截止时间是可调整的,而默认读期限短于写期限.这样就防止了写操作因为不能被读取而饿死的现象.
    Deadline对数据库环境(ORACLE RAC,MYSQL等)是最好的选择.
  4. AS(预料I/O调度程序)
    特点:
    本质上与Deadline一样,但在最后一次读操作后,要等待6ms,才能继续进行对其它I/O请求进行调度.
    可以从应用程序中预订一个新的读请求,改进读操作的执行,但以一些写操作为代价.
    它会在每个6ms中插入新的I/O操作,而会将一些小写入流合并成一个大写入流,用写入延时换取最大的写入吞吐量.
    AS适合于写入较多的环境,比如文件服务器
    AS对数据库环境表现很差.
    ** I/O调度算法总结 **
    Anticipatory I/O scheduler 适用于大多数环境,但不太合适数据库应用
    Deadline I/O scheduler 通常与Anticipatory相当,但更简洁小巧,更适合于数据库应用, DATA/SAS盘
    CFQ I/O scheduler 为所有进程分配等量的带宽,适合于桌面多任务及多媒体应用,默认IO调度器
    NOOP I/O scheduler 适用于SSD盘,有RAID卡,做了READ的盘

** sysctl.conf针对磁盘优化 **
vm.swappiness = [0 - 10] 默认是60,太高了,如果是缓存服务器建议配置为0

FileSystem

针对固态硬盘优化

  1. 关闭日志功能
    fstab里加挂载参数data=writeback
  2. 启用 TRIM 功能
    Linux内核从2.6.33开始提供TRIM支持,所以先运行“uname -a”命令,查看自己的内核版本,如果内核版本低于2.6.33的,请先升级内核。
    然后运行“hdparm -I /dev/sda”查看自己的硬盘支不支持TRIM技术,如果支持,你会看到
    Data Set Management TRIM supported
    如果上面两个条件都满足了,就可以在fstab中添加discard来开启TRIM功能,如:
    原始的UUID=2f6be0cf-2f54-4646-b8c6-5fb0aa01ef23 / ext4 defaults,errors=remount-ro 0 1
    改后的UUID=2f6be0cf-2f54-4646-b8c6-5fb0aa01ef23 / ext4 discard,defaults,errors=remount-ro 0 1

VFS(Virtual FileSystem) 虚拟文件系统

文件系统是内核的功能,是一种工作在内核空间的软件,访问一个文件必须要需要文件系统的存在才可以。Linux 可以支持多达数十种不同的文件系统,它们的实现各不相同,因此 Linux 内核向用户空间提供了虚拟文件系统这个统一的接口用来对文件系统进行操作。

图片 1

虚拟文件系统是位于用户空间进程和内核空间中多种不同的底层文件系统的实现之间的一个抽象的接口层,它提供了常见的文件系统对象模型(如 i-node, file object, page cache, directory entry, etc.)和访问这些对象的方法(如 open, close, delete, write, read, create, fstat, etc.),并将它们统一输出,类似于库的作用。从而向用户进程隐藏了各种不同的文件系统的具体实现,这样上层软件只需要和 VFS 进行交互而不必关系底层的文件系统,简化了软件的开发,也使得 linux 可以支持多种不同的文件系统。

Journaling

非日志型文件系统

在非日志型文件系统中,对文件系统实施一个写操作,内核会首先修改对应的元数据,然后修改数据块。如果在写入元数据时,文件系统发生崩溃或某种故障,那么数据的一致性将会遭到破坏。fsck 命令可以在下次重启时检查所有的元数据并修复数据一致性,但是如果文件系统非常大,或者系统运行关键业务不允许停机,使用非日志型文件系统的风险会非常高。

日志型文件系统

日志型文件系统的区别在于,在进行对文件系统写数据之前,写将数据写到「日志区」,然后再写入文件系统,在写入文件系统之后删除日志。日志区可以在文件系统内部也可以在文件系统外部。日志区的数据称作文件系统日志,这些数据包含了修改了的元数据,也可能包含将要修改的数据。写日志也会带来一定的额外开销。

EXT2

图片 2

ext2 文件系统组成不再赘述,需要注意的是 ext2 文件系统没有日志功能。

EXT3

ext3 是带有日志功能文件系统,它基于ext2文件系统实现。

  • 以一致性的方式写入数据,即使断电或文件系统崩溃,恢复的时间会大大减少
  • 数据完整性:在挂载时指定选项 data=journal 则可以使日志记录下元数据和文件数据
  • 速度:指定挂载选项 data=writeback 使用回写的方式写数据
  • 灵活性:可以从 ext2 系统升级,而不需要重新格式化文件系统,也可以以非日志模式挂载,就如同 ext2 一样

ext3的日志模式

  • journal,提供最大数据完整性,日志会记录元数据和文件数据
  • ordered,日志只记录元数据。但是会保证文件数据先被写入,这是默认选项。
  • writeback,使用回写的方式写数据,只保证记录元数据至日志。

其他文件系统

  • ReiserFS,ReiserFS是一个快速的日志型文件系统,有着良好的磁盘空间使用和快速的崩溃恢复。属于 Novell 公司,在 SUSE Linux 中使用。
  • JFS (Journal File System), JFS 是一个完全 64 位文件系统,可以支持非常大的文件和分区,早先由 IBM 公司为 AIX 操作系统开发,现已使用 GPL 协议开源。JFS适用于非常大的分区和文件如 HPC 或者数据库业务。
  • XFS (eXtended File System), 一个高性能的日志型文件系统,和 JFS 比较相似。

I/O子系统架构

图片 3

上图概括了一次磁盘 write 操作的过程,假设文件已经被从磁盘中读入了 page cache 中

  1. 一个用户进程通过 write() 系统调用发起写请求
  2. 内核更新对应的 page cache
  3. pdflush 内核线程将 page cache 写入至磁盘中
  4. 文件系统层将每一个 block buffer 存放为一个 bio 结构体,并向块设备层提交一个写请求
  5. 块设备层从上层接受到请求,执行 IO 调度操作,并将请求放入IO 请求队列中
  6. 设备驱动(如 SCSI 或其他设备驱动)完成写操作
  7. 磁盘设备固件执行对应的硬件操作,如磁盘的旋转,寻道等,数据被写入到磁盘扇区中

Block Layer

Block layer 处理所有和块设备相关的操作。block layer 最关键是数据结构是 bio 结构体。bio 结构体是 file system layer 到 block layer 的接口。 当执行一个写操作时,文件系统层将数据写入 page cache(由 block buffer 组成),将连续的块放到一起,组成 bio 结构体,然后将 bio 送至 block layer。

block layer 处理 bio 请求,并将这些请求链接成一个队列,称作 IO 请求队列,这个连接的操作就称作 IO 调度(也叫 IO elevator 即电梯算法).

IO scheduler

IO 调度器的总体目标是减少磁盘的寻道时间(因此调度器都是针对机械硬盘进行优化的),IO 调度器通过两种方式来减少磁盘寻道:合并排序

合并即当两个或多个 IO 请求的是相邻的磁盘扇区,那么就将这些请求合并为一个请求。通过合并请求,多个 IO 请求只需要向磁盘发送一个请求指令,减少了磁盘的开销。

排序就是将不能合并的 IO 请求,根据请求磁盘扇区的顺序,在请求队列中进行排序,使得磁头可以按照磁盘的旋转顺序的完成 IO 操作,可以减小磁盘的寻道次数。

调度器的算法和电梯运行的策略相似,因此 IO 调度器也被称作 IO 电梯( IO Elevator )。由于对请求进行了重排,一部分的请求可能会被延迟,以提升整体的性能。

Linux 2.4 只使用了一种通用的 IO 算法。到 Linux 2.6 实现了 4 种 IO 调度模型,其中 anticipatory 在 2.6.33 中被移除

Linus Elevator

早先的 IO 调度器就叫做 Linus Elevator,当一个请求被加入到请求队列中,它首先检查队列中是否存在相邻的请求以合并两个请求,这可能包含前合并和后合并。如果不能合并,则寻找是否能够将新请求按扇区顺序插入到请求队列,如果没有找到适合插入的位置,那么就将这个请求插入到队列的末尾。另外,如果请求队列中的某个请求超过的预先定义的过期阈值,新请求即使可以进行排序,也被插入到队列的末尾。这样可以防止磁盘上某个区域产生大量请求,而其他区域的请求被饿死。然而,这种过期策略并不十分高效。

这种算法可能导致请求饿死的情况,它是 Linux 2.4 的唯一调度器。

当一个请求加入到请求队列时,IO 调度器所完成的操作如下

  1. 如果队列中存在对相邻扇区的请求,则合并两个请求为一个
  2. 如果队列中存在超过过期时间的请求,那么新请求被插入到队列的末尾,以防止饿死老的请求
  3. 如果队列中存在可以按扇区地址排序的合适位置,那么将请求插入到这个位置
  4. 如果队列中没有合适的可插入位置,请求被插入到队列末尾

Deadline – latency-oriented

Deadline 调度器是设计用来解决 Linus Elevator 导致的 I/O 饿死的问题。对磁盘上某个区域的大量请求,会无限期的饿死 (starvation) 对磁盘其他区域上的请求。

请求饿死的一个特例是 写请求饿死读请求 (writes starving reads),对于进程来说,当需要进行写操作时,由于需要写的数据在内存的 page cache 中,进程是需要修改对应的内存,向内核发送写请求即可,之后进程可以去进行其他操作,由内核负责将数据同步至磁盘中即可。对于进程来说,写请求是异步操作。而读操作是完全不同的,当进程需要读取数据时,需要向内核发送读请求,内核将数据载入到内存中,由于进程往往需要处理读取的数据,因此进程将处于阻塞状态,直到请求被处理完成。对于进程来说,读请求是同步的操作。写请求延迟对系统的性能影响不大,而读请求延迟对系统性能影响是非常大的,因此两种 IO 请求需要区别对待。

Dealine 调度器专门针对读请求延迟进行了优化,在 deadline 算法中,每一个请求都有一个过期时间。默认情况下,读请求的过期时间是 500ms,写请求的过期时间是 5s。Dealine 调度器也会对请求队列进行合并和排序操作,这个队列称作排序队列(sorted queue)。当新请求被提交,Deadline将其加入到排序队列中进行合并和排序。同时 Deadline 将这个请求加入到第二种类型的队列中,读请求被加入至读FIFO队列 (Read FIFO queue),写请求被加入到写FIFO队列 (Write FIFO queue),这两个队列中,请求完全按照 FIFO 顺序排列,即新请求永远被放入到队列的末尾。

这样一来 Dealine 就维护三个队列,正常情况下,Deadline 将排序队列中的请求放入到调度队列 (dispatch queue,即将写入磁盘的队列)中,调度队列把请求发送至磁盘驱动。如果写 FIFO 队列或读 FIFO 队列中的请求发生了超时,Deadline 调度器就不再使用排序队列,而是开始将发生超时的 FIFO 队列的请求放入调度队列,直至队列中没有超时的请求,Deadline 通过这样的方式保证所有的请求都不会长时间超时。

图片 4

Deadling 防止了请求饿死的出现,由于读请求的超时时间远小于写请求,它同时也避免了出现写请求饿死读请求。

Deadline 比较适合于MySQL数据库。

Anticipatory(AS)

AS 调度器是基于 Deadline 调度器,加上了一个启发式的「预测」,假设系统中有大量的写请求,这时如果夹杂几个读请求,由于读请求的过期时间短,读请求立即在多个写请求的中间产生,这样会导致磁盘的来回寻道,AS 试图减少大量写请求夹杂少量读请求产生的寻道风暴(seek storm)。当一个读请求完成后,AS不会立即返回处理队列中的剩余请求,而是等待一个预测时间(默认为 6ms),如果等待的时间内发生了相邻位置的读请求,那么立即处理这个相邻位置的读请求,再返回处理队列中的请求,这样可以优化多余的寻道时间。

它可以为连续 IO 请求(如顺序读)进行了一定的优化,但是对于随机读的场景 AS 会产生较大的延迟,对于数据库应用很糟糕,而对于 Web Server 可能会表现的不错。这个算法也可以简单理解为面向低速磁盘的,对于使用了 TCG(Tagged Command Queueing)高性能的磁盘和 RAID,使用 AS 会降低性能。

在 Linux 2.6 – 2.6.18 AS 是内核默认调度器,然而大多数的企业发行版选择的是 CFQ 调度器。

到Linux 2.6.33 版本,AS 被从内核中移除,因为可以通过调整其他调度器(如 CFQ)来实现与其相似的功能。

Complete Fair Queuing(CFQ)- fairness-oriented

CFQ 为每个进程分配一个 I/O 请求队列,在每个队列的内部,进行合并和排序的优化。CFQ 以轮询的方式处理这些队列,每次从一个队列中处理特定数量的请求(默认为 4 个)。它试图将 I/O 带宽均匀的分配至每个进程。CFQ 原本针对的是多媒体或桌面应用场景,然而,CFQ 其实在许多场景中内表现的很好。CFQ 对每一个 IO 请求都是公平的。这使得 CFQ 很适合离散读的应用 (eg: OLTP DB)

多数企业发型版选择 CFQ 作为默认的 I/O 调度器。

NOOP(No Operation)

该算法实现了最简单的 FIFO 队列,所有 IO 请求按照大致的先后顺序进行操作。之所以说「大致」,原因是 NOOP 在 FIFO 的基础上还做了相邻 IO 请求的合并,但其不会进行排序操作。

NOOP 适用于底层硬件自身就具有很强调度控制器的块设备(如某些SAN设备),或者完全随机访问的块设备(如SSD)。

各个调度器在数据库应用下的性能,可以看出CFQ的性能是比较均衡的

图片 5

IO 参数调整

队列长度

查看队列长度

/sys/block/<dev>/queue/nr_requests

下图展示了各种队列长度时,Deadline 和 CFQ 调度器的性能

图片 6 图片 7

由 ext3 的表现可以看出,对于大量的小文件写操作,队列长度更长,性能会有所提升,在 16KB 左右,性能提升最为明显,在 64KB 时,64 至 8192 的队列长度有着差不多的性能。随着文件大小的增大,小队列长度反而有着更好的性能。 RHEL 操作系统中,每个设备有一个队列长度。对于类似数据库日志的存放分区,大部分写操作属于小文件 IO,可以将队列长度调小。

对于大量的连续读取,可以考虑增加读取首部的窗口大小

/sys/block/<dev>/queue/read_ahead_kb

IO调度器

选择设备的IO调度器

/sys/block/<dev>/queue/scheduler

或者在 grub.conf 中加入内核参数 elevator=SCHEDULER

本文由美高梅游戏平台网站发布于美高梅4858永利777,转载请注明出处:Linux 性能优化之 IO 子系统

关键词: