磁盘一般是计算机最慢的子系统,也是最容易出现性能瓶颈的地方,由于磁盘离 CPU 距离最远并且 CPU 访问磁盘要涉及到机械操做,好比转轴、寻轨等。访问硬盘和访问内存之间的速度差异是以数量级来计算的,就像1天和1分钟的差异同样。要监测 IO 性能,有必要了解一下基本原理和 Linux 是如何处理硬盘和内存之间的 IO 的。html
上一篇 Linux 性能监测:Memory 提到了内存和硬盘之间的 IO 是以页为单位来进行的,在 Linux 系统上1页的大小为 4K。能够用如下命令查看系统默认的页面大小:python
$ /usr/bin/time -v date ... Page size (bytes): 4096 ...
Linux 利用虚拟内存极大的扩展了程序地址空间,使得原来物理内存不能容下的程序也能够经过内存和硬盘之间的不断交换(把暂时不用的内存页交换到硬盘,把须要的内存页从硬盘读到内存)来赢得更多的内存,看起来就像物理内存被扩大了同样。事实上这个过程对程序是彻底透明的,程序彻底不用理会本身哪一部分、何时被交换进内存,一切都有内核的虚拟内存管理来完成。当程序启动的时候,Linux 内核首先检查 CPU 的缓存和物理内存,若是数据已经在内存里就忽略,若是数据不在内存里就引发一个缺页中断(Page Fault),而后从硬盘读取缺页,并把缺页缓存到物理内存里。缺页中断可分为主缺页中断(Major Page Fault)和次缺页中断(Minor Page Fault),要从磁盘读取数据而产生的中断是主缺页中断;数据已经被读入内存并被缓存起来,从内存缓存区中而不是直接从硬盘中读取数据而产生的中断是次缺页中断。linux
上面的内存缓存区起到了预读硬盘的做用,内核先在物理内存里寻找缺页,没有的话产生次缺页中断从内存缓存里找,若是尚未发现的话就从硬盘读取。很显然,把多余的内存拿出来作成内存缓存区提升了访问速度,这里还有一个命中率的问题,运气好的话若是每次缺页都能从内存缓存区读取的话将会极大提升性能。要提升命中率的一个简单方法就是增大内存缓存区面积,缓存区越大预存的页面就越多,命中率也会越高。下面的 time 命令能够用来查看某程序第一次启动的时候产生了多少主缺页中断和次缺页中断:ios
$ /usr/bin/time -v date ... Major (requiring I/O) page faults: 1 Minor (reclaiming a frame) page faults: 260 ...
从上面的内存缓存区(也叫文件缓存区 File Buffer Cache)读取页比从硬盘读取页要快得多,因此 Linux 内核但愿能尽量产生次缺页中断(从文件缓存区读),而且能尽量避免主缺页中断(从硬盘读),这样随着次缺页中断的增多,文件缓存区也逐步增大,直到系统只有少许可用物理内存的时候 Linux 才开始释放一些不用的页。咱们运行 Linux 一段时间后会发现虽然系统上运行的程序很少,可是可用内存老是不多,这样给你们形成了 Linux 对内存管理很低效的假象,事实上 Linux 把那些暂时不用的物理内存高效的利用起来作预存(内存缓存区)呢。下面打印的是 VPSee 的一台 Sun 服务器上的物理内存和文件缓存区的状况:数据库
$ cat /proc/meminfo MemTotal: 8182776 kB MemFree: 3053808 kB Buffers: 342704 kB Cached: 3972748 kB
这台服务器总共有 8GB 物理内存(MemTotal),3GB 左右可用内存(MemFree),343MB 左右用来作磁盘缓存(Buffers),4GB 左右用来作文件缓存区(Cached),可见 Linux 真的用了不少物理内存作 Cache,并且这个缓存区还能够不断增加。缓存
Linux 中内存页面有三种类型:服务器
Read pages,只读页(或代码页),那些经过主缺页中断从硬盘读取的页面,包括不能修改的静态文件、可执行文件、库文件等。当内核须要它们的时候把它们读到内存中,当内存不足的时候,内核就释放它们到空闲列表,当程序再次须要它们的时候须要经过缺页中断再次读到内存。app
Dirty pages,脏页,指那些在内存中被修改过的数据页,好比文本文件等。这些文件由 pdflush 负责同步到硬盘,内存不足的时候由 kswapd 和 pdflush 把数据写回硬盘并释放内存。ide
Anonymous pages,匿名页,那些属于某个进程可是又和任何文件无关联,不能被同步到硬盘上,内存不足的时候由 kswapd 负责将它们写到交换分区并释放内存。工具
每次磁盘 IO 请求都须要必定的时间,和访问内存比起来这个等待时间简直难以忍受。在一台 2001 年的典型 1GHz PC 上,磁盘随机访问一个 word 须要 8,000,000 nanosec = 8 millisec,顺序访问一个 word 须要 200 nanosec;而从内存访问一个 word 只须要 10 nanosec.(数据来自:Teach Yourself Programming in Ten Years)这个硬盘能够提供 125 次 IOPS(1000 ms / 8 ms)。
IO 可分为顺序 IO 和 随机 IO 两种,性能监测前须要弄清楚系统偏向顺序 IO 的应用仍是随机 IO 应用。顺序 IO 是指同时顺序请求大量数据,好比数据库执行大量的查询、流媒体服务等,顺序 IO 能够同时很快的移动大量数据。能够这样来评估 IOPS 的性能,用每秒读写 IO 字节数除以每秒读写 IOPS 数,rkB/s 除以 r/s,wkB/s 除以 w/s. 下面显示的是连续2秒的 IO 状况,可见每次 IO 写的数据是增长的(45060.00 / 99.00 = 455.15 KB per IO,54272.00 / 112.00 = 484.57 KB per IO)。相对随机 IO 而言,顺序 IO 更应该重视每次 IO 的吞吐能力(KB per IO):
$ iostat -kx 1 avg-cpu: %user %nice %system %iowait %steal %idle 0.00 0.00 2.50 25.25 0.00 72.25 Device:rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util sdb 24.00 19995.00 29.00 99.00 4228.00 45060.00 770.12 45.01 539.65 7.80 99.80 avg-cpu: %user %nice %system %iowait %steal %idle 0.00 0.00 1.00 30.67 0.00 68.33 Device:rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util sdb 3.00 12235.00 3.00 112.00 768.00 54272.00 957.22 144.85 576.44 8.70 100.10
随机 IO 是指随机请求数据,其 IO 速度不依赖于数据的大小和排列,依赖于磁盘的每秒能 IO 的次数,好比 Web 服务、Mail 服务等每次请求的数据都很小,随机 IO 每秒同时会有更多的请求数产生,因此磁盘的每秒能 IO 多少次是关键。
$ iostat -kx 1 avg-cpu: %user %nice %system %iowait %steal %idle 1.75 0.00 0.75 0.25 0.00 97.26 Device:rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util sdb 0.00 52.00 0.00 57.00 0.00 436.00 15.30 0.03 0.54 0.23 1.30 avg-cpu: %user %nice %system %iowait %steal %idle 1.75 0.00 0.75 0.25 0.00 97.24 Device:rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util sdb 0.00 56.44 0.00 66.34 0.00 491.09 14.81 0.04 0.54 0.19 1.29
按照上面的公式得出:436.00 / 57.00 = 7.65 KB per IO,491.09 / 66.34 = 7.40 KB per IO. 与顺序 IO 比较发现,随机 IO 的 KB per IO 小到能够忽略不计,可见对于随机 IO 而言重要的是每秒能 IOPS 的次数,而不是每次 IO 的吞吐能力(KB per IO)。
当系统没有足够物理内存来应付全部请求的时候就会用到 swap 设备,swap 设备能够是一个文件,也能够是一个磁盘分区。不过要当心的是,使用 swap 的代价很是大。若是系统没有物理内存可用,就会频繁 swapping,若是 swap 设备和程序正要访问的数据在同一个文件系统上,那会碰到严重的 IO 问题,最终致使整个系统迟缓,甚至崩溃。swap 设备和内存之间的 swapping 情况是判断 Linux 系统性能的重要参考,咱们已经有不少工具能够用来监测 swap 和 swapping 状况,好比:top、cat /proc/meminfo、vmstat 等:
$ cat /proc/meminfo MemTotal: 8182776 kB MemFree: 2125476 kB Buffers: 347952 kB Cached: 4892024 kB SwapCached: 112 kB ... SwapTotal: 4096564 kB SwapFree: 4096424 kB ... $ vmstat 1 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 2 260008 2188 144 6824 11824 2584 12664 2584 1347 1174 14 0 0 86 0 2 1 262140 2964 128 5852 24912 17304 24952 17304 4737 2341 86 10 0 0 4