=======================io性能分析篇=======================
相关概念:
1.文件系统:本身对存储设备上的文件,进行组织管理的机制。组织方式不同,就会形成不同的文件系统。
2.为了方便管理,Linux文件系统为每个文件都分配两个数据结构,索引节点和目录项。它们主要用来记录文件的元信息和目录结构
*索引节点:简称inode,用来记录文件的元数据,比如inode编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。
*目录项:简称dentry,用来记录文件的名字、索引节点指针以及其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不过,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存。
3.磁盘读写的最小单位是扇区,为了提高磁盘的读写效率,文件系统又把连续的扇区组成了逻辑块,每次都以逻辑块为最小单元来管理数据。常见的逻辑块大小为4kb,也就是连续的8个扇区。一个扇区512B
4.注意点:
*目录项本身就是一个内存缓存,而索引节点则是存储在磁盘中的数据。为了协调慢速磁盘与快速CPU的性能差异,文件内容会缓存在页缓存cache中。
*磁盘在执行文件系统格式化时,会被分成三个存储区域:超级快、索引节点区和数据块区
超级块:存储整个文件的状态
索引节点区:用来存储索引节点
数据块区:用来存储文件数据
5.文件系统的四大要素:目录项、索引节点、逻辑块以及超级块
6.为了支持各种不同的文件系统,Linux内核在用户进程和文件系统中间,又引入了一个抽象层,也就是虚拟文件系统VFS(virtual file system)
7.VFS定义了一组所有文件系统都支持的数据结构和标准接口。这样,用户进程和内核中的其他子系统,只需要跟VFS提供的统一接口进行交互就可以了,不需要关系底层各种文件系统的实现细节。
8.各种文件系统按照层次分类:
第一类:基于磁盘的文件系统,也就是把数据直接存储到计算机本地挂载的磁盘中。常见的ext4、xfs、overlayfs等。
第二类:基于内存的文件系统,也就是我们常说的虚拟文件系统。这类文件系统,不需要任何磁盘分配存储空间,但会占用内存。我们经常用到的/proc文件系统,就是一种最常用的文件系统。此外,/sys文件系统也属于这一类,主要向用户空间导出层次化的内核对象。
第三类:网络文件系统,也就是用来访问其他计算机数据的文件系统,比如NFS、SMB、ISCSI等。
9.把文件系统挂载到挂载点后,就能通过挂载点访问它管理的文件了。VFS提供了一组标准的文件访问接口。这些接口以系统调用的方,提供给程序使用。
如:cat命令,它首先调用open()调用,打开一个文件,然后调用read()调用,读取文件的内容,最后再用write()调用,把文件内容输出到控制台的标准输出中。
10.文件读写方式的各种差异,导致i/o的分类多种多样。最常见的有:缓冲与非缓冲io、直接与非直接io、阻塞与非阻塞io、同步与异步io等。
11.各种io类型解释:
第一种:根据是否利用标准库缓存,可以把文件 I/O 分为缓冲 I/O 与非缓冲 I/O。
缓冲io:是指利用标准库缓存来加速文件的访问,而标准库内部则通过系统调度访问文件。
非缓冲io:是指直接通过系统调用来访问文件,不在经过标准库缓存。注,这里说的"缓冲",是指标准文件库内部实现的缓存。比方说,你可能见过,很多程序遇到换行时才真正输出,而换行前的内容,其实就是被标准库暂时缓存了起来。
第二种:根据是否利用操作系统的页缓存,直接跟文件系统交互来访问文件
直接io(裸io/raw io):是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件
非直接io:正好相反,文件读写时,先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘。
注:要想实现直接io,需要你在文件系统调用中,指定O_DIRECT标志,如果没有设置过,默认是非直接IO
第三种:根据应用程序是否阻塞自身运行,可以把文件io分为阻塞io和非阻塞io
阻塞io:是指应用程序执行io操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务
非阻塞io:是指应用程序执行io操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果。
如:访问管道或者网络套接字时,设置O_NONBLOCK标志,就表示用非阻塞方式访问;而如果不做任何设置,默认的就是阻塞访问。
第四种:根据是否等待响应结果,可以把文件io分为同步和异步io
同步io:是指应用程序执行io操作后,要一直等到整个io完成后,才能获得io响应
异步io:是指应用程序执行io操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次io完成后,响应会用事件通知的方式告诉应用程序。
如1:在操作文件时,如果你设置了 O_SYNC 或者 O_DSYNC 标志,就代表同步 I/O。如果设置了 O_DSYNC,就要等文件数据写入磁盘后,才能返回;而 O_SYNC,则是在 O_DSYNC 基础上,要求文件元数据也要写入磁盘后,才能返回。
如2:在访问管道或者网络套接字时,设置了 O_ASYNC 选项后,相应的 I/O 就是异步 I/O。这样,内核会再通过 SIGIO 或者 SIGPOLL,来通知进程文件是否可读写。
=========================================================================================
缓存的相关查看使用:
1.命令df -h查看磁盘使用量,df -i查看inode节点信息
2.free 输出的 Cache,是页缓存和可回收 Slab 缓存的和,你可以从 /proc/meminfo:cat /proc/meminfo |grep -E "SReclaimable|Cached"
3.内核使用 Slab 机制,管理目录项和索引节点的缓存。/proc/meminfo 只给出了 Slab 的整体大小,具体到每一种 Slab 缓存,还要查看 /proc/slabinfo 这个文件。
4.所有目录项和各种文件系统索引节点的缓存情况:cat /proc/slabinfo |grep -E '^#|dentry|inode'
5.通过命令slabtop来找到占用内存最多的缓存类型,按下 c 按照缓存大小排序,按下 a 按照活跃对象数排序
=========================================================================================
磁盘:
1.机械磁盘与固态磁盘:
第一类,机械磁盘,也称为硬盘驱动器(Hard Disk Driver),通常缩写为HDD。机械磁盘主要由盘片和读写磁头组成,数据就存储在盘片的环状磁道中。在读写数据前,需要移动读写磁头,定位到数据所在的磁道,然后才能访问数据。显然,如果I/O请求刚好连续,那就不需要磁道寻址,自然可以获得最佳性能。这其实就是我们熟悉的,连续I/O的工作原理。与之相对应的,当然就是随机I/O,它需要不停地移动磁头,来定位数据位置,所以读写速度就会比较慢。
第二类,固态磁盘(SolidStateDisk),通常缩写为SSD,由固态电子元器件组成。固态磁盘不需要磁道寻址,所以,不管是连续 I/O,还是随机 I/O的性能,都比机械磁盘要好得多。其实,无论机械磁盘,还是固态磁盘,相同磁盘的随机 I/O 都要比连续 I/O 慢很多,原因也很明显。
2.按接口进行磁盘介质分类
硬盘分为 IDE(Integrated Drive Electronics)、SCSI(Small Computer SystemInterface) 、SAS(Serial Attached SCSI) 、SATA(Serial ATA) 、FC(FibreChannel) 等。
3.IDE设备会分配一个hd前缀的设备名,SCSI和SATA设备会分配一个sd前缀的设备名。如果是多块同类型的磁盘,就会按照a、b、c 等的字母顺序来编号。
4.磁盘的使用架构
*直接作为独立磁盘设备来使用,可以根据需求化为不同的分区
*根据容量、性能和可靠性的考量,可以将磁盘组合成不同的raid级别
*把这些磁盘组合成一个网络存储集群,在通过NFS、SMB、ISCSI等网络协议,暴露给服务器使用。
5.通用块层
a.与虚拟文件系统类似,为了减少不同块设备的差异带来的影响,Linux通过一个统一的通用块层,来管理不同的块设备
b.第一功能:向上,为文系统和应用程序,提供访问块设备的标准接口;向下,把各种异构的磁盘设备抽象为统一的块设备,并提供统一框架来管理这些设备的驱动程序。
c.第二功能:通用快层还会给文件系统和应用程序发来的io请求排队,并通过重新排序、请求合并等方式,提高磁盘的读写效率。
d.对io请求排序的过程,也就是我们熟悉的io调度。事实上,Linux内核支持四种io调度算法,分别是NONE、NOOP、CFQ以及DeadLine.
e.第一种NONE,更确切的来说,并不能算io调度算法。因为它完全不使用任何io调度器,对文件系统和应用程序的io其实不做任何处理,常用在虚拟机中(此时磁盘io调度完全有物理机负责)
f.第二种NOOP,是最简单的一种io调度算法,它实际上是一个先入先出的队列,只做一些最基本的请求合并,常用于SSD
g.第三种CFQ,也被称为完全公平调度器,是现在很多发行版的默认io调度器,它为每个进程维护一个io调度队列,并按照时间片来均匀分布每个进程io请求。类似于进程CPU调度,CFQ还支持进程io的优先级调度,所以它适用于运行大量进程的系统,像是桌面环境、多媒体应用等。
h.最后一种DeadLine调度算法,分布为读、写请求创建了不同的io队列,可以提高机械磁盘的吞吐量,并确保达到最终期限deadline的请求被优先处理。deadline调度算法,多用在io压力比较重的场景,比如数据库等。
6.io栈
a.我们可以吧Linux存储系统的io栈,由上到下分为三个层次,分别是文件系统层、通用块层和设备层。
b.文件系统层,包括虚拟文件系统和其他各种文件系统的具体实现。它为上层的应用程序,提供标准的文件访问接口;对下会通过通用块层,来存储和管理磁盘数据。
c.通用块层,包括块设备io队列和io调度器。它会对文件系统的io请求进行排队,再通过重新排序和请求合并,然后才发送给下一级的设备层。
d.设备层,包括存储设备和相应的驱动程序,负责最终物理设备的io操作。
e.存储系统的io,通常是整个系统中最慢的一环。所以,Linux通过多种缓存机制来优化io效率。
f.为了优化存储系统访问文件的性能,会使用页缓存、索引节点缓存、目录项缓存等多种缓存机制,以及减少对下层块设备的直接调用。
g.为了优化块设备的访问效率,会使用缓冲区,来缓存块设备的数据。
=================================================================================
磁盘性能指标:.
1.磁盘性能基本指标
使用率:是指磁盘处理io的时间百分比。过高的使用率(比如超过80%),通常意味着磁盘io存在性能瓶颈。
饱和度:是指磁盘处理io的繁忙程度。过高的饱和度,意味着磁盘存在着严重的性能瓶颈。当饱和度为100%时,磁盘无法接受新的io请求。
IOPS:是指每秒的io请求数,适用于大量小文件的情景
吞吐量:是指每秒的io请求大小,适用与大文件的情景
响应时间:是指io请求从发出到收到响应的时间间隔
2.测试工具 fio ,来测试磁盘的 IOPS、吞吐量以及响应时间等核心指标
3.磁盘io观测:iostat是最常用的磁盘I/O性能观测工具,它提供了每个磁盘的使用率、IOPS、吞吐量等各种常见的性能指标,当然,这些指标实际上来自 /proc/diskstats。
4.iostat -d -x 1 #-d -x 表示显示所有磁盘io的操作
%util ,就是我们前面提到的磁盘 I/O 使用率;
r/s+ w/s ,就是 IOPS;
rkB/s+wkB/s ,就是吞吐量;
r_await+w_await ,就是响应时间。
5.pidstat -d 1 #查看具体进程的io情况
用户 ID(UID)和进程 ID(PID) 。
每秒读取的数据大小(kB_rd/s) ,单位是 KB。
每秒发出的写请求数据大小(kB_wr/s) ,单位是 KB。
每秒取消的写请求数据大小(kB_ccwr/s) ,单位是 KB。
块 I/O 延迟(iodelay),包括等待同步块 I/O 和换入块 I/O 结束的时间,单位是时钟周期。
6.iotop命令可以io大小对进程进行排序
==================================================================================
案例一:io问题分析案例
top---iostat -x -d 1---pidstat -d 1/iotop---strace -p 进程号---lsof -p 进程号---修复---测试
查看buffer/cache占用,建议使用pcstat或者hcache,hcache是基于pcstat的,pcstat可以查看某个文件是否被缓存和根据进程pid来查看都缓存了哪些文件。hcache在其基础上增加了查看整个操作系统Cache和根据使用Cache大小排序的特性。
Buffers 是内核缓冲区用到的内存,对应的是 /proc/meminfo 中的 Buffers 值。
Cache 是内核页缓存和 Slab 用到的内存,对应的是 /proc/meminfo 中的 Cached 与SReclaimable 之和。
Buffers是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据,通常不会特别大(20MB左右)。这样,内核就可以把分散的写集中起来,统一优化磁盘的写入,比如可以把多次小的写合并成单次大的写等等。
Cached是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据。这样,下次访问这些文件数据时,就可以直接从内存中快速获取,而不需要再次访问缓慢的磁盘
==================================================================================
案例二:io问题分析案例
top--iostat -x -d 1---pidstat -d 1/iotop---strace -p 进程号---无法定位到进程正在调用磁盘io---动态追踪工具filetop命令---查看到进程创建了大量文件---opensnoop命令定位创建文件的位置---查看目录发现没有文件---在观察一段时间opensnoop发现文件变了---说明文件是动态生成的---查看之前异常的进程源码---确认问题根因
由于进程创建的文件为临时文件,strace命令没法动态查看到文件的创建删除,所以无法定位问题。此时,借助工具filetop/opensnoop动态跟踪命令追踪进程的执行情况。
注:使用filetop/opensnoop命令需要安装bcc软件包,opensnoop 。它同属于 bcc 软件包,可以动态跟踪内核中的
open 系统调用
在strace -p PID后加上-f,多进程和多线程都可以跟踪
==================================================================================
案例三:数据库io问题案例
top---iostat -d -x 1---pidstat -d 1/iotop---strace -f -p 进程号,追踪线程级别的调用。可以去掉-f追踪进程级别---lsof -p 进程号,没有内容输出,并且echo $?显示为1,这是由于前面strace命令输出的线程号,lsof是指定进程号---通过线程号ps查看进程号---pstree -f -a -p 进程号,可以看出线程与进程的对应关系---lsof -p 进程号---查看到对应的文件为数据库表结构文件---查看数据库数据文件show global variables like "%datadir%";---排除数据库储存文件位置不一样的问题---进入数据库查看进程show full processlist;---确认具体执行的慢语句---explain 执行的语句---查看具体sql语句是什么问题---没有走索引---show create table 表---查看创表语句---定位到问题---范围查询导致慢查询
注:echo 1>/proc/sys/vm/drop_caches表示释放pagecache,也就是文件缓存,而mysql读书的数据就是文件缓存,dataservice不停的释放文件缓存,就导致MySQL都无法利用磁盘缓存
=================================================================================
案例四:数据库redis io问题案例
top---iostat -d -x 1---pidstat -d 1---strace/lsof--nsenter
安装nsenter命令:
docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter
nsenter命令可以指定进程执行命令:
容器中使用nsenter命令:
# 由于这两个容器共享同一个网络命名空间,所以我们只需要进入 app 的网络命名空间即可
$ PID=$(docker inspect --format {{.State.Pid}} app)
# -i 表示显示网络套接字信息
$ nsenter --target $PID --net -- lsof -i
docker环境设置redis配置:
docker exec -it redis redis-cli config set appendfsync everysec
=================================================================================
磁盘的性能指标:
容量、使用量、剩余量、索引节点
页缓存、目录项缓存、索引节点缓存以及各文件系统缓存、
IOPS(包括 r/s 和 w/s)、响应时间(延迟)以及吞吐量(B/s)等
******性能工具分析总结:
第一,在文件系统的原理中,我介绍了查看文件系统容量的工具 df。它既可以查看文件系统数据的空间容量,也可以查看索引节点的容量。至于文件系统缓存,我们通过 /proc/meminfo、/proc/slabinfo 以及 slabtop 等各种来源,观察页缓存、目录项缓存、索引节点缓存以及具体文件系统的缓存情况。
第二,在磁盘 I/O 的原理中,我们分别用 iostat 和 pidstat 观察了磁盘和进程的 I/O 情况。它们都是最常用的 I/O 性能分析工具。通过 iostat ,我们可以得到磁盘的 I/O 使用率、吞吐量、响应时间以及 IOPS 等性能指标;而通过 pidstat ,则可以观察到进程的 I/O 吞吐量以及块设备 I/O 的延迟等。
第三,在狂打日志的案例中,我们先用 top 查看系统的 CPU 使用情况,发现 iowait 比较高;然后,又用 iostat 发现了磁盘的 I/O 使用率瓶颈,并用 pidstat 找出了大量 I/O 的进程;最后,通过 strace 和 lsof,我们找出了问题进程正在读写的文件,并最终锁定性能问题的来源——原来是进程在狂打日志。
第四,在磁盘 I/O 延迟的单词热度案例中,我们同样先用 top、iostat ,发现磁盘有 I/O 瓶颈,并用 pidstat 找出了大量 I/O 的进程。可接下来,想要照搬上次操作的我们失败了。在随后的 strace 命令中,我们居然没看到 write 系统调用。于是,我们换了一个思路,用新工具 filetop 和 opensnoop ,从内核中跟踪系统调用,最终找出瓶颈的来源。
最后,在 MySQL 和 Redis 的案例中,同样的思路,我们先用 top、iostat 以及 pidstat ,确定并找出 I/O 性能问题的瓶颈来源,它们正是 mysqld 和 redis-server。随后,我们又用 strace+lsof 找出了它们正在读写的文件。
==================================================================================
*****文件系统和磁盘io分析方式:
1.先用 iostat 发现磁盘 I/O 性能瓶颈;
2.再借助 pidstat ,定位出导致瓶颈的进程;
3.随后分析进程的 I/O 行为;
4.最后,结合应用程序的原理,分析这些 I/O 的来源。
==================================================================================
***fio命令对磁盘的测试:
# 随机读
fio -name=randread -direct=1 -iodepth=64 -rw=randread -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
# 随机写
fio -name=randwrite -direct=1 -iodepth=64 -rw=randwrite -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
# 顺序读
fio -name=read -direct=1 -iodepth=64 -rw=read -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
# 顺序写
fio -name=write -direct=1 -iodepth=64 -rw=write -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
***参数:
direct,表示是否跳过系统缓存。上面示例中,我设置的 1 ,就表示跳过系统缓存。
iodepth,表示使用异步 I/O(asynchronous I/O,简称 AIO)时,同时发出的 I/O 请求上限。在上面的示例中,我设置的是 64。
rw,表示 I/O 模式。我的示例中, read/write 分别表示顺序读 / 写,而 randread/randwrite 则分别表示随机读 / 写。
ioengine,表示 I/O 引擎,它支持同步(sync)、异步(libaio)、内存映射(mmap)、网络(net)等各种 I/O 引擎。上面示例中,我设置的 libaio 表示使用异步 I/O。
bs,表示 I/O 的大小。示例中,我设置成了 4K(这也是默认值)。
filename,表示文件路径,当然,它可以是磁盘路径(测试磁盘性能),也可以是文件路径(测试文件系统性能)。示例中,我把它设置成了磁盘 /dev/sdb。不过注意,用磁盘路径测试写,会破坏这个磁盘中的文件系统,所以在使用前,你一定要事先做好数据备份。
报告指标:
slat ,是指从 I/O 提交到实际执行 I/O 的时长(Submission latency);
clat ,是指从 I/O 提交到 I/O 完成的时长(Completion latency);
而 lat ,指的是从 fio 创建 I/O 到 I/O 完成的总时长。
======================================================================================
*****blktrace命令记录磁盘的io访问情况在通过fio重放:
# 使用 blktrace 跟踪磁盘 I/O,注意指定应用程序正在操作的磁盘
$ blktrace /dev/sdb
# 查看 blktrace 记录的结果
# ls
sdb.blktrace.0 sdb.blktrace.1
# 将结果转化为二进制文件
$ blkparse sdb -d sdb.bin
# 使用 fio 重放日志
$ fio --name=replay --filename=/dev/sdb --direct=1 --read_iolog=sdb.bin
这样,我们就通过 blktrace+fio 的组合使用,得到了应用程序 I/O 模式的基准测试报告
=====================================================================================
******应用程序io性能优化:
第一,可以用追加写代替随机写,减少寻址开销,加快 I/O 写的速度。
第二,可以借助缓存 I/O ,充分利用系统缓存,降低实际 I/O 的次数。
第三,可以在应用程序内部构建自己的缓存,或者用 Redis 这类外部缓存系统。这样,一方面,能在应用程序内部,控制缓存的数据和生命周期;另一方面,也能降低其他应用程序使用缓存对自身的影响。
第四,在需要频繁读写同一块磁盘空间时,可以用 mmap 代替 read/write,减少内存的拷贝次数。
第五,在需要同步写的场景中,尽量将写请求合并,而不是让每个请求都同步写入磁盘,即可以用 fsync() 取代 O_SYNC。
第六,在多个应用程序共享相同磁盘时,为了保证 I/O 不被某个应用完全占用,推荐你使用 cgroups 的 I/O 子系统,来限制进程 / 进程组的 IOPS 以及吞吐量。
最后,在使用 CFQ 调度器时,可以用 ionice 来调整进程的 I/O 调度优先级,特别是提高核心应用的 I/O 优先级。ionice 支持三个优先级类:Idle、Best-effort 和 Realtime。其中, Best-effort 和 Realtime 还分别支持 0-7 的级别,数值越小,则表示优先级别越高。
=====================================================================================
******文件系统优化:
第一,你可以根据实际负载场景的不同,选择最适合的文件系统。比如 Ubuntu 默认使用 ext4 文件系统,而 CentOS 7 默认使用 xfs 文件系统。
相比于 ext4 ,xfs 支持更大的磁盘分区和更大的文件数量,如 xfs 支持大于 16TB 的磁盘。但是 xfs 文件系统的缺点在于无法收缩,而 ext4 则可以。
第二,在选好文件系统后,还可以进一步优化文件系统的配置选项,包括文件系统的特性(如 ext_attr、dir_index)、日志模式(如 journal、ordered、writeback)、挂载选项(如 noatime)等等。
比如, 使用 tune2fs 这个工具,可以调整文件系统的特性(tune2fs 也常用来查看文件系统超级块的内容)。 而通过 /etc/fstab ,或者 mount 命令行参数,我们可以调整文件系统的日志模式和挂载选项等。
第三,可以优化文件系统的缓存。
比如,你可以优化 pdflush 脏页的刷新频率(比如设置 dirty_expire_centisecs 和 dirty_writeback_centisecs)以及脏页的限额(比如调整 dirty_background_ratio 和 dirty_ratio 等)。
再如,你还可以优化内核回收目录项缓存和索引节点缓存的倾向,即调整 vfs_cache_pressure(/proc/sys/vm/vfs_cache_pressure,默认值 100),数值越大,就表示越容易回收。
最后,在不需要持久化时,你还可以用内存文件系统 tmpfs,以获得更好的 I/O 性能 。tmpfs 把数据直接保存在内存中,而不是磁盘中。比如 /dev/shm/ ,就是大多数 Linux 默认配置的一个内存文件系统,它的大小默认为总内存的一半。
=======================================================================================
磁盘优化:
第一,最简单有效的优化方法,就是换用性能更好的磁盘,比如用 SSD 替代 HDD。
第二,我们可以使用 RAID ,把多块磁盘组合成一个逻辑磁盘,构成冗余独立磁盘阵列。这样做既可以提高数据的可靠性,又可以提升数据的访问性能。
第三,针对磁盘和应用程序 I/O 模式的特征,我们可以选择最适合的 I/O 调度算法。比方说,SSD 和虚拟机中的磁盘,通常用的是 noop 调度算法。而数据库应用,我更推荐使用 deadline 算法。
第四,我们可以对应用程序的数据,进行磁盘级别的隔离。比如,我们可以为日志、数据库等 I/O 压力比较重的应用,配置单独的磁盘。
第五,在顺序读比较多的场景中,我们可以增大磁盘的预读数据,比如,你可以通过下面两种方法,调整 /dev/sdb 的预读大小。
调整内核选项 /sys/block/sdb/queue/read_ahead_kb,默认大小是 128 KB,单位为 KB。
使用 blockdev 工具设置,比如 blockdev --setra 8192 /dev/sdb,注意这里的单位是 512B(0.5KB),所以它的数值总是 read_ahead_kb 的两倍。
第六,我们可以优化内核块设备 I/O 的选项。比如,可以调整磁盘队列的长度 /sys/block/sdb/queue/nr_requests,适当增大队列长度,可以提升磁盘的吞吐量(当然也会导致 I/O 延迟增大)。
最后,要注意,磁盘本身出现硬件错误,也会导致 I/O 性能急剧下降,所以发现磁盘性能急剧下降时,你还需要确认,磁盘本身是不是出现了硬件错误。
比如,你可以查看 dmesg 中是否有硬件 I/O 故障的日志。 还可以使用 badblocks、smartctl 等工具,检测磁盘的硬件问题,或用 e2fsck 等来检测文件系统的错误。如果发现问题,你可以使用 fsck 等工具来修复。
=====================================================================================
阻塞、非阻塞 I/O 与同步、异步 I/O 的区别:
阻塞 / 非阻塞和同步 / 异步,其实就是两个不同角度的 I/O 划分方式。它们描述的对象也不同,阻塞 / 非阻塞针对的是 I/O 调用者(即应用程序),而同步 / 异步针对的是 I/O 执行者(即系统)。
当应用程序请求系统调用时,系统调用完就结束了,处理其他事务去了,而程序要阻塞在哪等待返回结果。对于应用程序来说就是阻塞io,对于系统调用来说就是异步io