在这些情况下I/O会成为系统的瓶颈。我们会用到工具top,vmstat,iostat,sar等。每一个工具的输出都从不同的方面反映除系统的性能情况。在服务器的性能中,往往性能的瓶颈都集中在磁盘的IO上。
情况1:同一时间进行大量的I/O操作
[root@10dian69 6268]# 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 0 1366232 515516 54140 81412 0 0 458 321 1 0 1 1 97 1 0
1 0 1366232 514112 54140 81408 0 0 40736 8 3888 8465 3 3 88 7 0
1 0 1366232 514128 54140 81412 0 0 40560 0 3202 8078 3 3 88 7 0
0 1 1366232 514144 54140 81412 0 0 40192 0 3218 8055 3 2 88 7 0
0 1 1366232 514144 54140 81412 0 0 40016 0 3240 8065 3 2 88 7 0
1 0 1366232 514764 54164 81412 0 0 39552 84 3202 7974 3 3 88 7 0
1 0 1366232 514764 54172 81404 0 0 39168 32 3142 7887 3 2 88 7 0
1 0 1366232 513888 54172 81408 0 0 40240 4 3539 8216 3 2 88 7 0
0 1 1366232 513888 54172 81412 0 0 40256 0 3156 8029 3 2 88 7 0
1 0 1366232 513896 54172 81412 0 0 40352 0 3206 8088 3 2 88 7 0
0 1 1366232 514148 54172 81412 0 0 40576 0 3199 8126 3 3 88 7 0
2 0 1366148 514272 54172 81420 32 0 38560 0 5624 10834 5 3 85 7 0
0 1 1366148 514272 54188 81408 0 0 39280 40 3164 7930 3 2 88 7 0
1 1 1366148 512952 54188 81412 0 0 39936 8 3866 8396 3 3 88 7 0
0 1 1366148 513160 54188 81412 0 0 40592 0 3177 8102 3 2 88 7 0
从这个输出我们可以看到CPU有50%的时间都在等待I/O操作,我们还可以看到系统的bi值很大,证明系统有大量的I/O请求将磁盘内容读入内存。
没有很好的工具能看到到底是哪个进程在进行I/O读写。但我们可以通过top命令的输出来猜测。
<pre name="code" class="plain">[root@10dian69 6268]# top -d 1
top - 18:45:38 up 79 days, 8 min, 4 users, load average: 1.00, 1.03, 0.91
Tasks: 209 total, 1 running, 208 sleeping, 0 stopped, 0 zombie
Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 98.0%id, 2.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu1 : 22.6%us, 19.4%sy, 0.0%ni, 0.0%id, 58.1%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu2 : 0.0%us, 0.0%sy, 0.0%ni, 99.0%id, 1.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu4 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu5 : 1.0%us, 1.0%sy, 0.0%ni, 98.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu6 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu7 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 32814004k total, 32300236k used, 513768k free, 54380k buffers
Swap: 32767992k total, 1366148k used, 31401844k free, 81408k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6268 mysql 20 0 6509m 5.7g 4396 S 39.6 18.1 189:36.84 mysqld
59 root 20 0 0 0 0 S 2.0 0.0 155:10.55 kblockd/1
4429 mysql 20 0 13.8g 13g 4760 S 1.0 41.7 132:56.98 mysqld
7274 root 20 0 15152 1348 964 R 1.0 0.0 0:00.14 top
1 root 20 0 19364 980 760 S 0.0 0.0 0:04.96 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.99 kthreadd
3 root RT 0 0 0 0 S 0.0 0.0 0:12.29 migration/0
4 root 20 0 0 0 0 S 0.0 0.0 0:14.78 ksoftirqd/0
5 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
6 root RT 0 0 0 0 S 0.0 0.0 0:09.47 watchdog/0
7 root RT 0 0 0 0 S 0.0 0.0 2:02.69 migration/1
8 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/1
9 root 20 0 0 0 0 S 0.0 0.0 0:30.15 ksoftirqd/1
10 root RT 0 0 0 0 S 0.0 0.0 0:06.54 watchdog/1
11 root RT 0 0 0 0 S 0.0 0.0 0:41.76 migration/2
12 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/2
情况2:管道太小
任何I/O操作都需要一定的时间,而且这些时间对于硬盘来说是确定的,它包含磁盘旋转的延时RD(rotation delay)和磁头搜索时间DS(disk seek)。RD由磁盘转速(RPM)决定。RD是磁盘旋转一周所需时间的一半。如RPM为10000.
RPS=RPM/60=166
1/166=0.0006=6ms磁盘旋转一周要6毫秒
RD=6ms/2=3ms
磁盘平均搜索时间是3ms,数据传输的平均延时是2ms,这样一次I/O操作的平均时间是:
3ms+3ms+2ms=8ms
IOPS=1000/8=125 这块磁盘的每秒IO数(IOPS)为125。所以对于10000RPM的磁盘来说它所能承受的IO操作在IOPS在120~150之间。如果系统的I/O请求超过这个值,就会使磁盘成为系统的瓶颈。
对与系统而言有两种不同种类的I/O压力,连续I/O和随机I/O。
连续I/O常常出现在企业级数据库这样的应用中,需要连续的读取大量数据。这种系统的性能依靠它读取和移动数据的大小和快慢。我们用iostat来监控,会发现rKB/s,wKB/s会很高。
[root@10dian69 6268]# iostat
Linux 2.6.32-431.el6.x86_64 (10dian69) 09/24/2014 _x86_64_ (8 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.99 0.00 0.50 1.22 0.00 97.29
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
sda 0.86 19.15 32.08 130708194 219005736
sdc 75.44 2339.58 3781.69 15970838570 25815181856
sdb 153.41 4958.18 1313.01 33846292266 8963055184
对于随机I/O的系统来说性能的关注点不在搜传输数据的大小和速度,而是在磁盘的IOPS。这类系统的I/O请求比较小但是数量很大,如Web服务器和Mail服务器。他们的性能主要依赖每秒钟可处理的请求数:
[root@10dian69 6268]# iostat -x 1
Linux 2.6.32-431.el6.x86_64 (10dian69) 09/24/2014 _x86_64_ (8 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.99 0.00 0.50 1.22 0.00 97.29
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sda 0.17 3.27 0.12 0.74 19.14 32.08 59.47 0.03 37.32 4.95 0.43
sdc 4.22 395.96 68.58 6.84 2339.19 3781.05 81.15 0.54 7.14 0.68 5.12
sdb 5.55 140.63 149.49 3.90 4957.33 1312.78 40.88 0.43 2.79 0.31 4.69
avg-cpu: %user %nice %system %iowait %steal %idle
0.00 0.00 0.00 0.00 0.00 100.00
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdc 0.00 0.00 2.00 0.00 64.00 0.00 32.00 0.00 1.50 1.50 0.30
sdb 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
因此对于连续I/O系统来说我们要关注系统读取大量数据的能力即KB per request.对于随机I/O系统我们注重IOPS值.
IO系统是整个系统中最慢的部分,因为它需要真正的物理操作磁盘的转动和检索。比起内存来要差几个数量级。Linux内核将硬盘IO分页,每一页的大小默认为4K。这时,内存和磁盘的读写以页为单位进行,这些页叫做内存页。
用time命令可以检查页的大小:
[root@10dian69 6268]# /usr/bin/time -v date
Wed Sep 24 19:10:21 CST 2014
Command being timed: "date"
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 3088
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 231
Voluntary context switches: 1
Involuntary context switches: 2
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
主要页错误(Major Page Faults)和次要页错误(Minor Page Faults):
MPF(Major Page Faults)表示进程需要的数据并不在内存中,需要从磁盘读取。
一旦内存页读入到内存的缓冲区中,程序就在内存中读取或写入数据,叫做MnPF(Minor Page Faults)。MnPF通过重复使用内存页而缩短了内核时间。Time命令可以显示一个进程中MPF和MnPF的数量,在evolution程序第一次启动的时候会有很多MPF:
[root@10dian69 6268]# /usr/bin/time -v evolution
/usr/bin/time: cannot run evolution: No such file or directory
Command exited with non-zero status 127
Command being timed: "evolution"
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 976
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 50
Voluntary context switches: 1
Involuntary context switches: 0
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 127
如果再次启动evolution程序,我们就看到MPF消失了,因为此时进程需要的数据已经全部在内存中了:
[root@10dian69 6268]# /usr/bin/time -v evolution
/usr/bin/time: cannot run evolution: No such file or directory
Command exited with non-zero status 127
Command being timed: "evolution"
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: ?%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 960
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 49
Voluntary context switches: 1
Involuntary context switches: 0
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 127
当进程不断的进行IO操作的时候,系统会将这些数据缓存到内存中。所以我们会看到系统的FreeMemory越来越少,而Cache越来越大。如下:
[root@10dian69 6268]# cat /proc/meminfo
MemTotal: 32814004 kB
MemFree: 509280 kB
Buffers: 59288 kB
Cached: 81760 kB
SwapCached: 424968 kB
Active: 28396892 kB
Inactive: 3454240 kB
Active(anon): 28320508 kB
Inactive(anon): 3389592 kB
Active(file): 76384 kB
Inactive(file): 64648 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 32767992 kB
SwapFree: 31402584 kB
Dirty: 32 kB
Writeback: 0 kB
AnonPages: 31376476 kB
Mapped: 9844 kB
Shmem: 16 kB
Slab: 137936 kB
SReclaimable: 64248 kB
SUnreclaim: 73688 kB
KernelStack: 11152 kB
PageTables: 69472 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 49174992 kB
Committed_AS: 34900916 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 338020 kB
VmallocChunk: 34341200864 kB
HardwareCorrupted: 0 kB
AnonHugePages: 29253632 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 6400 kB
DirectMap2M: 33484800 kB
有些人为系统的可用内存太少而担心,而事实不是这样,这种情况恰恰证明系统正在高效的利用cache,进而减少MPF,增加MnPF。但从这个输出我们无法断定内存是否为系统瓶颈。
前面讲了内存页的定义,接下来我们说说内存页的分类:
1. Read Pages-这些页通过MPF从磁盘读入,并且是只读的。这些页存在与cache中包括不能修改的静态文件,二进制文件,库文件。内核在需要的时候会将他们读入内存,当内存资源紧张时,内核会释一些放此类的内存页,当程序在此需要的时候,就只能通过MPF重新读入。
2. Dirty Pages-这些页是内核在内存中修改过的页面。这些页面需要同步回磁盘上。Pdflush负责将他们写回磁盘。当内存不够时,kswapd就会触发pdflush将页面写回磁盘以释放内存。
3. Anonymous Pages-这些页属于某个进程,但是没有任何磁盘文件与之相关。他们不能和磁盘同步。当内存不够时,kswapd会将他们写入swap分区。
应用程序可以用系统调用fsync()和sync()将Dirty Page立即写回磁盘。如果应用程序没有调用此类函数,pdflush进程会定期与磁盘进行同步。