Linux IO优化
的笔记,内容很浅,可以用作入门《Linux性能优化》
读书笔记整理vmstat
统计系统内磁盘分区I/O的性能iostat
分析磁盘分区的饱和度,利用率,读写速率。lsof
确定哪些进程正在使用一组给定的文件,从而确认进行磁盘IO的进程Linux基础
,存储相关知识「 总感觉当下的生活不是想要的,总感觉一路走下去会是一个讨厌的未来,每天睁眼的一瞬间就是懊悔,昨天又浪费掉了...人生没有意义,但是要努力寻找活着的意义--------山河已无恙」
在Linux中,我们可以通过一些性能工具评估磁盘I/O子系统的使用情况。展示那些磁盘或分区已被使用,每个磁盘处理了多少I/O,发给这些磁盘的I/O请求要等多久才被处理。
在学习性能工具之前,我们来了解Linux磁盘I/O系统是怎样构成的。
大多数现代Linux系统都有一个或多个磁盘驱动。SCSI驱动则常常被命名为sda、sdb、sdc等。
┌──[root@vms81.liruilongs.github.io]-[/]
└─$lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 200G 0 disk
|-sda1 8:1 0 150G 0 part /
`-sda2 8:2 0 10G 0 part
磁盘通常要分为多个分区,分区设备名称的创建方法是在基础驱动名称的后面直接添加分区编号。
一般每个独立分区要么包含一个文件系统,要么包含一个交换分区。当然也可以是一个VDO卷,分区被挂载到Linux文件系统,由/etc/fstab
指定。
在Linux 中,我们可以直接对磁盘进行分区,使用文件系统格式化,也使用LVM的方式来使用管理磁盘,大多数情况下,是通过LVM来管理Linux存储。利用LVM,化零为整,可以对数据卷进行统一分配,动态扩容。关于LVM(PV,VG,LV),感兴趣小伙伴可以看看我之前的博文。
分区或者逻辑卷被指定文件系统格式化后,挂载目录。即可存放应用程序要读写的文件。
当一个应用程序进行读写时,Linux内核可以在其高速缓存或缓冲区中保存文件的副本,并且可以在不访问磁盘的情况下返回被请求的信息。但是,如果Linux内核没有在内存中保存数据副本,那它就向磁盘 I/O 队列添加一个请求。
若Linux内核注意到多个请求都指向磁盘内相邻的区域,它会把它们合并为一个大的请求。这种合并能消除第二次请求的寻道时间
, 以此来提高磁盘整体性能。
当请求被放入磁盘队列,而磁盘当前不忙时,它就开始为IO请求服务。如果磁盘正忙,则请求就在队列中等待,直到该设备可用,请求将被服务。这里的等待,即我们在编程中讲的IO阻塞,尤其在涉及的并发的问题中,我们常常要考虑线程I/O阻塞情况来调整线程优先级,Java在JDK1.4 的版本中,提供NIO(采用内存映射文件的方式处理,将文件或文件的一段区域映射到内存中)来提高访问效率。
vmstat是一个强大的工具,它能给出系统在性能方面的总览图。除了CPU和内存统计信息之外,vmstat还可以提供系统整体上的I/O性能情况。
我们用的版本
┌──[root@vms81.liruilongs.github.io]-[/]
└─$vmstat -V
vmstat from procps-ng 3.3.10
┌──[root@vms81.liruilongs.github.io]-[/]
└─$which vmstat
/usr/bin/vmstat
vmstat超过其他I/O工具的主要优势是:几乎所有的Linux发行版本都包含该工具。同时 vmstat提供的扩展磁盘统计信息只用于内核版本高于2.5.70的Linux系统
在使用vmstat从系统获取磁盘1/0统计信息时,要按照如下方式进行调用:
vmstat [-D] [-d] [-p partition] [interval [count]]
命令行选项
选项 | 描述 |
---|---|
-D | 显示Linux I/O子系统总的统计数据。它可以让你很好地了解你的IO子系统是如何被使用的,但它不会给出单个磁盘的统计数据。显示的统计数据是从系统启动.开始的总信息,而不是两次采样之间的发生量 |
-d | 按每interval一个样本的速率显示单个磁盘的统计数据。这些统计信息是从系统启动开始的总信息,而不是两次采样之间的发生量 |
-p partition | 按照每interval一个采样的速率显示给定分区的性能统计数据。这些统计信息是从系统启动开始的总信息,而不是两次采样之间的发生量 |
interval | 采样之间的时间间隔 |
count | 所取的样本总数 |
在用-D模式运行时, vmstat提供的是系统内磁盘10系统的总体统计数据。
┌──[root@vms81.liruilongs.github.io]-[/]
└─$vmstat -D
1 disks
2 partitions
14661 total reads
33 merged reads
3369384 read sectors
16091 milli reading
521150 writes
5093 merged writes
5189564 written sectors
110797 milli writing
0 inprogress IO
86 milli spent IO
参数 | 说明 |
---|---|
disks | 系统中的磁盘总数 |
partitions | 系统中的分区总数 |
total reads | 读请求总数 |
merged reads | 为了提升性能而被合并的不同读请求数量,这些读请求访问的是磁盘上的相邻位置 |
read sectors | 从磁盘读取的扇区总数(一个扇区通常为512字节) |
milli reading | 磁盘读所花费的时间(以毫秒为单位) |
writes | 写请求的总数 |
merged writes | 为了提升性能而被合并的不同写请求数量,这些写请求访问的是磁盘上的相邻位置 |
written sectors | 向磁盘写入的扇区总数(一个扇区通常为512字节) |
milli writing | 磁盘写所花费的时间(以毫秒为单位) |
inprogress IO | 当前正在处理的10总数。请注意,最近版本(v3.2)的vmstat在这里有个漏洞,除以1000时其结果是错误的,几乎总是得到。 |
milli spent IO | 等待1/0完成所花费的毫秒数。请注意,最近版本(v3.2)的vmstat在这里有个漏洞,其数值为1/0花费的秒数,而非毫秒数 |
如果你在运行vmstat时只使用了[interval]和[count]参数,其他参数没有使用,那么显示的就是默认输出。该输出中包含了三列与磁盘1/0性能相关的内容: bo, bi和wa。
┌──[root@vms81.liruilongs.github.io]-[/]
└─$vmstat 1 2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 243708 2072 1748600 0 0 13 21 55 107 2 3 95 0 0
0 0 0 242768 2072 1748604 0 0 0 32 3352 5026 4 3 93 0 0
┌──[root@vms81.liruilongs.github.io]-[/]
└─$
列名 | 说明 |
---|---|
bo | 表示前次间隔中被写入磁盘的总块数(vmstat内磁盘的典型块大小为1024字节) |
bi | 表示前次间隔中从磁盘读出的块数(vmstat内磁盘的典型块大小为1024字节) |
wa | 表示等待1/0完成所消耗的CPU时间。每秒写磁盘块的速率 |
使用vmstat取样3个样本,时间间隔为1秒
┌──[root@vms81.liruilongs.github.io]-[/]
└─$vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 209244 2072 1751828 0 0 13 20 88 160 2 3 95 0 0
0 0 0 209040 2072 1751828 0 0 0 12 3182 4760 2 3 95 0 0
0 0 0 209028 2072 1751828 0 0 0 58 3053 4668 2 3 96 0 0
┌──[root@vms81.liruilongs.github.io]-[/]
└─$
我们可以看到,在第一秒的时候,io读取13块,写入了20块,第二读取0,写入12块,磁盘块的大小为1024字节,即系统读取速率为13/1024,等待IO的时间为O,说明当前系统IO读写空闲
vmstat的-d选项显示的是每一个磁盘的I/O统计信息。这些统计数据与-D选项的数据类似
┌──[root@vms81.liruilongs.github.io]-[/]
└─$vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
total merged sectors ms total merged sectors ms cur sec
sda 14661 33 3369384 16091 523799 5120 5213233 111242 0 86
统计数据 | 说明 |
---|---|
reads:total | 读请求的总数 |
reads:merged | 为了提升性能而被合并的不同读请求数量,这些读请求访问的是磁盘上的相邻位置 |
reads:sectors | 从磁盘读取的扇区总数 |
reads:ms | 磁盘读所花费的时间(以毫秒为单位) |
writes:total | 写请求的总数 |
writes:merged | 为了提升性能而被合并的不同写请求数量,这些写请求访问的是磁盘上的相邻位置 |
writes:sectors | 向磁盘写人的扇区总数(一个扇区通常为512字节) |
writes:ms | 磁盘写所花费的时间(以毫秒为单位)当前正在处理的I/O总数 |
IO:cur | 当前正在处理的I/O总数。 |
10:sec | 等待1/0完成所花费的秒数 |
[root@foundation0 ~]# vmstat -d 1 2
disk- ------------reads------------ ------------writes----------- -----IO------
total merged sectors ms total merged sectors ms cur sec
nvme0n1 72865 5 6560405 54580 138514 1015 6715558 94026 0 149
sr0 0 0 0 0 0 0 0 0 0 0
loop0 49 0 2308 10 0 0 0 0 0 0
loop1 93 0 19822 146 0 0 0 0 0 0
loop2 77 0 3764 20 0 0 0 0 0 0
loop3 88 0 20882 73 0 0 0 0 0 0
loop4 463 0 64058 1904 0 0 0 0 0 0
nvme0n1 72865 5 6560405 54580 138514 1015 6715558 94026 0 149
sr0 0 0 0 0 0 0 0 0 0 0
loop0 49 0 2308 10 0 0 0 0 0 0
loop1 93 0 19822 146 0 0 0 0 0 0
loop2 77 0 3764 20 0 0 0 0 0 0
loop3 88 0 20882 73 0 0 0 0 0 0
loop4 463 0 64058 1904 0 0 0 0 0 0
[root@foundation0 ~]#
┌──[root@vms81.liruilongs.github.io]-[/]
└─$vmstat -p sda1 1 3
sda1 reads read sectors writes requested writes
15036 3381024 545880 5414724
15036 3381024 545894 5414837
15036 3381024 545895 5414846
上面我们可以看到,对于sda1物理分区来讲,有14(545880-545894)个写提交了
虽然vmstat提供了单个磁盘/分区的统计信息,但是它只给出其总量,却不给出在采样过程中的变化率。因此,要分辨哪个设备的统计数据在采样期间发生了明显的变化就显得很困难。
iostat与vmstat相似,但它是一个专门用于显示磁盘1/0子系统统计信息的工具。
iostat提供的信息细化到每个设备和每个分区从特定磁盘读写了多少个块。(iostat中块大小一般为512字节。)
此外,iostat还可以提供大量的信息来显示磁盘是如何被利用的,以及Linux花费了多长时间来等待将请求提交到磁盘。
iostat用如下命令行调用:
iostat [-d] [-k] [-x] [devicel] [interval[count]]
与vmstat很相似,iostat可以定期显示性能统计信息。
选项 | 说明 |
---|---|
-d | 只显示磁盘I/O的统计信息,而不是默认信息。默认信息中还包括了CPU使用情况 |
-k | 按KB显示统计数据,而不是按块显示 |
-x | 显示扩展性能I/O统计信息 |
device | 若指定设备,则iostat只显示该设备的信息 |
interval | 采样间隔时间 |
count | 获取的样本总数 |
iostat设备统计信息
┌──[root@vms81.liruilongs.github.io]-[/]
└─$iostat
Linux 3.10.0-693.el7.x86_64 (vms81.liruilongs.github.io) 06/14/22 _x86_64_ (2 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
2.42 0.00 2.94 0.01 0.00 94.63
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
sda 8.18 24.59 39.45 1694748 2718599
统计数据 | 说明 |
---|---|
tps | 每秒传输次数。该项为每秒对设备/分区读写请求的次数 |
kB_read/s | 每秒读取磁盘块的速率 |
kB_wrtn/s | 每秒写入磁盘块的速率 |
kB_read | 在时间间隔内读取块的总数量 |
kB_wrtn | 在时间间隔内写入块的总数量 |
┌──[root@vms81.liruilongs.github.io]-[/]
└─$iostat -d 1 3
Linux 3.10.0-693.el7.x86_64 (vms81.liruilongs.github.io) 06/14/22 _x86_64_ (2 CPU)
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
sda 8.17 24.33 39.40 1694756 2744300
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
sda 9.00 0.00 37.00 0 37
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
sda 0.00 0.00 0.00 0 0
┌──[root@vms81.liruilongs.github.io]-[/]
└─$
当你使用-x参数调用iostat时,它会显示更多关于磁盘I/O子系统的统计信息。
┌──[root@vms81.liruilongs.github.io]-[/]
└─$iostat -x -dk 1 3 /dev/sda1
Linux 3.10.0-693.el7.x86_64 (vms81.liruilongs.github.io) 06/14/22 _x86_64_ (2 CPU)
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda1 0.00 0.08 0.22 7.96 24.21 39.39 15.57 0.00 0.23 1.10 0.21 0.16 0.13
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda1 0.00 0.00 0.00 15.00 0.00 60.00 8.00 0.00 0.27 0.00 0.27 0.27 0.40
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda1 0.00 0.00 0.00 8.00 0.00 32.00 8.00 0.00 0.25 0.00 0.25 0.25 0.20
┌──[root@vms81.liruilongs.github.io]-[/]
└─$
iostat的扩展磁盘统计信息
统计数据 | 说明 |
---|---|
rrqm/s | 在提交给磁盘前,被合并的读请求的数量 |
wrqm/s | 在提交给磁盘前,被合并的写请求的数量 |
r/s | 每秒提交给磁盘的读请求数量 |
w/s | 每秒提交给磁盘的写请求数量 |
rsec/s | 每秒读取的磁盘扇区数 |
wsec/s | 每秒写入的磁盘扇区数 |
rkB/s | 每秒从磁盘读取了多少KB的数据 |
wkB/s | 每秒向磁盘写入了多少KB的数据 |
avgrq-sz | 磁盘请求的平均大小(按扇区计) |
avgqu-sz | 磁盘请求队列的平均大小。 |
await | 完成对一个请求的服务所需的平均时间(按毫秒计),该平均时间为请求在磁盘队列中等待的时间加上磁盘对其服务所需的时间 |
svctm | 提交到磁盘的请求的平均服务时间(按毫秒计)。该项表明磁盘完成一个请求所花费的平均时间。与await不同,该项不包含在队列中等待的时间 |
%util | 利用率 |
当avgqu-sz的值特别大的时候,且请求等待时间await远远高于请求服务svctm所花费时间,且利用率%util为100%的时候,表明该磁盘处于饱和状态。
sar可以收集Linux系统多个不同方面的性能统计信息。除了CPU和内存之外,它还可以收集关于磁盘I/O子系统的信息。
当使用sar 来监视磁盘I/O统计数据时,你可以用如下命令行来调用它:
sar -d [interval [count] ]
通常,sar显示的是系统中CPU使用的相关信息。若要显示磁盘使用情况的统计信息,你必须使用-d选项。sar只能在高于2.5.70的内核版本中显示磁盘I/O统计数据。
显示信息进行了说明。
┌──[root@vms81.liruilongs.github.io]-[/]
└─$sar -d 1 3
Linux 3.10.0-693.el7.x86_64 (vms81.liruilongs.github.io) 06/14/22 _x86_64_ (2 CPU)
23:31:21 DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
23:31:22 dev8-0 7.00 0.00 56.00 8.00 0.00 0.29 0.29 0.20
23:31:22 DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
23:31:23 dev8-0 1.00 0.00 10.00 10.00 0.00 0.00 0.00 0.00
23:31:23 DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
23:31:24 dev8-0 12.00 0.00 96.00 8.00 0.00 0.33 0.25 0.30
Average: DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
Average: dev8-0 6.67 0.00 54.00 8.10 0.00 0.30 0.25 0.17
┌──[root@vms81.liruilongs.github.io]-[/]
└─$
统计数据 | 说明 |
---|---|
tps | 每秒传输数。该项为每秒对设备/分区进行读写的次数 |
rd_sec/s | 每秒读取的磁盘扇区数 |
wr_sec/s | 每秒写入的磁盘扇区数 |
avgrq-sz | 磁盘请求的平均大小(按扇区计) |
avgqu-sz | 磁盘请求队列的平均大小。 |
await | 完成对一个请求的服务所需的平均时间(按毫秒计),该平均时间为请求在磁盘队列中等待的时间加上磁盘对其服务所需的时间 |
svctm | 提交到磁盘的请求的平均服务时间(按毫秒计)。该项表明磁盘完成一个请求所花费的平均时间。与await不同,该项不包含在队列中等待的时间 |
%util | 利用率 |
1sof提供了一种方法来确定哪些进程打开了一个特定的文件。除了跟踪单个文件的用户外,lsof还可以显示使用了特定目录下文件的进程。同时,它还可以递归搜索整个目录树,并列出使用了该目录树内文件的进程。在要筛选哪些应用程序产生了I/O时,lsof是很有用的。
你可以使用如下命令行调用lsof来找出进程打开了哪些文件:
1sof [-r delay] [+D directory] [+d directory] [file]
┌──[root@vms81.liruilongs.github.io]-[/]
└─$yum -y install lsof
通常,lsof显示的是使用给定文件的进程。但是,通过使用+d和+D选项,它可以显示多个文件的相关信息。表6-10解释了1sof的命令行选项,它们可用于追踪I/O性能问题。
sof 命令行选项
选项 | 说明 |
---|---|
-r delay | 使得1sof每间隔delay秒输出一次统计数据 |
+D directory | 使得1sof递归搜索给定目录下的所有文件,并报告哪些进程正在使用它们 |
+d directory | 使得1sof报告哪些进程正在使用给定目录下的文件 |
┌──[root@vms81.liruilongs.github.io]-[/]
└─$lsof -r 2 +D /usr/bin/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dbus-daem 539 dbus txt REG 8,1 442080 268592945 /usr/bin/dbus-daemon
VGAuthSer 544 root txt REG 8,1 128488 268979997 /usr/bin/VGAuthService
vmtoolsd 545 root txt REG 8,1 48976 268980000 /usr/bin/vmtoolsd
firewalld 636 root txt REG 8,1 7136 268591652 /usr/bin/python2.7
tuned 951 root txt REG 8,1 7136 268591652 /usr/bin/python2.7
kubelet 957 root txt REG 8,1 153350040 270317939 /usr/bin/kubelet
container 961 root txt REG 8,1 48766984 268964765 /usr/bin/containerd
dockerd 1073 root txt REG 8,1 96765968 268963237 /usr/bin/dockerd
container 1735 root txt REG 8,1 8617984 268592410 /usr/bin/containerd-shim-runc-v2
container 1782 root txt REG 8,1 8617984 268592410 /usr/bin/containerd-shim-runc-v2
container 1853 root txt REG 8,1 8617984 268592410 /usr/bin/containerd-shim-runc-v
统计数据 | 说明 |
---|---|
COMMAND | 打开该文件的命令的名称 |
PID | 打开该文件的命令的PID |
USER | 打开文件的用户 |
FD | 该文件的描述符。txt表示可执行文件,mem表示内存映射文件TYPE文件类型,REG表示常规文件 |
DEVICE | 用主设备号和次设备号表示的设备编号 |
SIZE | 文件的大小 |
NODE | 文件的索引节点 |
可以通过DEVICE来查看对应的设备位置
┌──[root@vms81.liruilongs.github.io]-[/]
└─$ls -la /dev/ | grep sd
brw-rw---- 1 root disk 8, 0 Jun 12 14:58 sda
brw-rw---- 1 root disk 8, 1 Jun 12 14:58 sda1
brw-rw---- 1 root disk 8, 2 Jun 12 14:58 sda2
┌──[root@vms81.liruilongs.github.io]-[/]
└─$
当我们通过前面的命令确定了饱和的磁盘设备。那么我们可以通过lsof来根据磁盘找到对应的文件,从而确认对应的PID