frank1234 阅读(388) 评论(0)
1.概述
由于IO速度相对于内存和CPU会慢很多,所以磁盘IO操作很容易成为性能瓶颈,对于有磁盘操作的应用,都应该监控磁盘IO。

Java应用造成磁盘IO消耗严重,主要是多个线程需要进行大量内容写入(例如频繁的日志写入),或者操作的文件本身很大。

任何减少磁盘IO的策略都有帮助,例如使用BufferedInputStream,使用缓存,使用NIO等。
2.iostat命令
# iostat 2
Linux 2.6.32-71.el6.i686 (centos)       06/24/2014      _i686_  (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          28.03    0.00   11.32    2.07    0.00   58.59

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda              11.34       526.84        50.90     212084      20490
dm-0             28.56       503.56        50.76     202714      20432
dm-1              0.80         6.40         0.00       2576          0
命令格式:
iostat [ -c | -d ] [ -k | -m ] [ -t ] [ -V ] [ -x ] [ device [ ... ] | ALL ] [ -p [ device | ALL ]  ]
       [ interval [ count ] ]

1)各个输出项目的含义如下:
avg-cpu段:
%user: 在用户级别运行所使用的CPU的百分比.
%nice: nice操作所使用的CPU的百分比.
%system: 在系统级别(kernel)运行所使用CPU的百分比.
%iowait: CPU等待硬件I/O时,所占用CPU百分比.
%idle: CPU空闲时间的百分比.
Device段:
tps: 每秒钟发送到的I/O请求数.
Blk_read /s: 每秒读取的block数.
Blk_wrtn/s: 每秒写入的block数.
Blk_read:   读入的block总数.
Blk_wrtn:  写入的block总数.
2)iostat参 数说明
iostat各个参数说明:
-c 仅显示CPU统计信息.与-d选项互斥.
-d 仅显示磁盘统计信息.与-c选项互斥.
-k 以K为单位显示每秒的磁盘请求数,默认单位块.
-p device | ALL
  与-x选项互斥,用于显示块设备及系统分区的统计信息.也可以在-p后指定一个设备名,如:
# iostat -p hda
  或显示所有设备
# iostat -p ALL
-t    在输出数据时,打印搜集数据的时间.
-V    打印版本号和帮助信息.
-x    输出扩展信息.

3.iostat -xm 命令
#iostat -xm 2
Linux 2.6.32-71.el6.i686 (centos)       06/24/2014      _i686_  (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          25.38    0.00   10.25    1.88    0.00   62.48

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda              14.54     4.37    8.71    1.60     0.23     0.02    50.78     0.10    9.37   3.05   3.14
dm-0              0.00     0.00   20.11    5.78     0.22     0.02    19.39     0.53   20.52   1.20   3.11
dm-1              0.00     0.00    0.72    0.00     0.00     0.00     8.00     0.00    1.26   0.68   0.05

1)各个输出项目的含义如下:
avg-cpu段:
同上
Device段:
rrqm/s  : 每秒被合并的读请求数
wrqm/s  :每秒被合并的写请求数
r/s     :每秒读的请求数
w/s    :每秒写的请求数
rMB/s    :每秒读的数据量,单位MB
wMB/s   :每秒写的数据量,单位MB
avgrq-sz :等待请求的平均大小(扇区)
avgqu-sz  :等待请求的平均队列长度
await  :平均每次IO操作的等待时间
svctm  : 平均每次设备执行IO操作的时间
%util  :每秒钟IO操作占用的百分比,%util=(r/s+w/s)*(svctm/1000) ,所以该值可能会超过100%

形象的比喻:
r/s+w/s 类似于交款人的总数
平均队列长度(avgqu-sz)类似于单位时间里平均排队人的个数
平均服务时间(svctm)类似于收银员的收款速度
平均等待时间(await)类似于平均每人的等待时间
平均I/O数据(avgrq-sz)类似于平均每人所买的东西多少
I/O 操作率 (%util)类似于收款台前有人排队的时间比例

如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;如果 await 远大于 svctm,说明 I/O 队列太长,应用得到的响应时间变慢。

重点关注加红加粗内容。
4.iotop命令
#iotop  --监控进程对IO的使用情况,top类IO监控
Total DISK READ: 0.00 B/s | Total DISK WRITE: 0.00 B/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND                      
2048 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % console-kit-daemon --no-daemon
    1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % init
    2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
    3 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/0]
    4 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]
    5 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdog/0]
    6 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [events/0]
    7 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [cpuset]
    8 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [khelper]
    9 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [netns]
   10 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [async/mgr]
   11 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [pm]
   12 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [sync_supers]
   13 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [bdi-default]
   14 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kintegrityd/0]
   15 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kblockd/0]
   16 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kacpid]
   17 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kacpi_notify]
   18 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kacpi_hotplug]
   19 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ata/0]
   20 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ata_aux]

TID  :进程Id
PRIO  :优先级
USER    :用户
DISK READ  :每秒读取数据量
DISK WRITE  :每秒写入数据量
SWAPIN     :磁盘交换百分比
IO>    :IO占用百分比
COMMAND :命令

5.vmstat命令
#vmstat 3
procs -----------memory---------- --------------swap-- ---------------io---- --------system-- -----cpu-----
r  b   swpd   free   buff  cache    si     so   bi    bo   in   cs  us  sy id  wa st
0  0  90340  26756  20396 214080  503    1     0   100   90  206  0  1 95   3  0
0  0  90340  26756  20396 214084    0    0     0     0   58  144  0  0 100  0  0
0  0  90340  26632  20404 214084   48    0     0     0   85  185  0  0 100  0  0
0  0  90340  26632  20404 214084    0    0     0     0   63  145  0  0 100  0  0
0  0  90340  26632  20404 214084   43    0     0     0   80  176  0  0 100  0  0
0  0  90340  26632  20404 214084    0    0     0     0   69  155  0  0 100  0  0
0  0  90340  26632  20412 214084   16    0     0     0   76  174  0  1 99   0  0
0  0  90340  26632  20412 214084    0    0     0     0   76  160  0  0 100  0  0

bi --发送到块设备的块数,单位块/s
bo --从块设备接收的块数,单位块/s
wa --IO等待占用的CPU百分比
其他参数解释,见CPU篇。

加红加粗内容为磁盘IO有关的资源使用情况。
6.pidstat命令
#pidstat -p <pid> -d -t 1  2
Linux 2.6.32-71.el6.i686 (centos)       06/24/2014      _i686_  (1 CPU)

08:29:45 AM      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
08:29:46 AM      2574         -      0.00    216.00      0.00  java
08:29:46 AM         -      2574      0.00      0.00      0.00  |__java
08:29:46 AM         -      2575      0.00      0.00      0.00  |__java
08:29:46 AM         -      2576      0.00      0.00      0.00  |__java
08:29:46 AM         -      2577      0.00      0.00      0.00  |__java
08:29:46 AM         -      2578      0.00      0.00      0.00  |__java
08:29:46 AM         -      2579      0.00      0.00      0.00  |__java
08:29:46 AM         -      2580      0.00      0.00      0.00  |__java
08:29:46 AM         -      2581      0.00      0.00      0.00  |__java
08:29:46 AM         -      2582      0.00      0.00      0.00  |__java
08:29:46 AM         -      2583      0.00    216.00      0.00  |__java

08:29:46 AM      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
08:29:47 AM      2574         -      0.00    234.34      0.00  java
08:29:47 AM         -      2574      0.00      0.00      0.00  |__java
08:29:47 AM         -      2575      0.00      0.00      0.00  |__java
08:29:47 AM         -      2576      0.00      0.00      0.00  |__java
08:29:47 AM         -      2577      0.00      0.00      0.00  |__java
08:29:47 AM         -      2578      0.00      0.00      0.00  |__java
08:29:47 AM         -      2579      0.00      0.00      0.00  |__java
08:29:47 AM         -      2580      0.00      0.00      0.00  |__java
08:29:47 AM         -      2581      0.00      0.00      0.00  |__java
08:29:47 AM         -      2582      0.00      0.00      0.00  |__java
08:29:47 AM         -      2583      0.00    234.34      0.00  |__java


参数解释:
TGID : 进程Id
TID  : 线程Id
kB_rd/s : 每秒读取数据量,单位KB  
kB_wr/s : 每秒写入数据量,单位KB
kB_ccwr/s  : 写入磁盘的已取消的任务的字节数量,单位KB
Command : 执行命令

由上可见线程2583执行了大量的IO操作,可以抓取线程快照,获取对应的java代码,具体抓取办法见4. -CPU篇。
7.统计磁盘IO最高的10个进程
1)开启IO监控
#sysctl vm.block_dump=1或echo 1 >/proc/sys/vm/block_dump
2)开启后内核会将IO读写dump到日记,可以用dmesg查看
#dmesg
3)统计当前占用IO最高的10个进程
# dmesg |awk -F: '{print $1}'|sort|uniq -c|sort -rn|head -n 10

387 pci 0000
     84 pci_bus 0000
     64 pcieport 0000
     64 pciehp 0000
     40 ACPI
     38   alloc kstat_irqs on node -1
     34 SELinux
     33 acpiphp
     32 acpiphp_glue
     12 dracut


8.磁盘IO资源瓶颈
如果%util 和 %iowait 很高,说明系统存在磁盘IO瓶颈,需要具体分析IO消耗。
9.磁盘IO占用代码示例
代码:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.Random;


public class IOHighDemo {
private String fileName = "/tmp/iowait.log";
private static int threadCount = Runtime.getRuntime().availableProcessors();
private Random random = new Random();
public static void main(String[] args) throws Exception{
IOHighDemo demo = new IOHighDemo();
demo.runTest();
}
private void runTest() throws Exception{
File file = new File(fileName);
file.createNewFile();
for(int i=0;i<threadCount;i++){
new Thread(new Task()).start();
}
}
class Task implements Runnable{
public void run(){
while(true){
try{
BufferedWriter writer = new BufferedWriter(new FileWriter(fileName,true));
StringBuilder strBuilder = new StringBuilder("====begin====\n");
String threadName = Thread.currentThread().getName();
for(int i=0;i<100000;i++){
strBuilder.append(threadName);
strBuilder.append("\n");
}
strBuilder.append("=====end=====\n");
writer.write(strBuilder.toString());
writer.close();
Thread.sleep(random.nextInt(10));

}catch(Exception e){
e.printStackTrace();
}
}
}
}
}

运行结果:
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          49.47    0.00   33.68    0.00    0.00   16.84

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.00 16709.47    0.00  162.11     0.00    65.90   832.62    58.69  362.02  10.63 172.32
dm-0              0.00     0.00    0.00 16871.58     0.00    65.90     8.00  6970.27  413.14   0.10 172.32
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00

结果说明:
1)%util很高,说明有大量的磁盘IO操作。

10.参考资料
《Java性能优化权威指南》
葛一鸣:《Java性能优化》
林昊:《分布式Java应用:基础与实践》
http://aofengblog.blog.163.com/blog/static/6317021201331365716412/
http://www.tuicool.com/articles/YRRJNbq
http://www.douban.com/note/231085095/
http://blog.csdn.net/wyzxg/article/details/3985221
http://www.2cto.com/os/201303/192123.html
http://blog.slogra.com/post-317.html