xiaobaoqiu Blog

Think More, Code Less

Vmstat工具

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。

1.常用参数

一般vmstat工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数

参数1表示每隔1秒打印一条信息

1
2
3
4
5
6
7
8
9
10
xiaobaoqiu@xiaobaoqiu:~/hotel/CRM/fs$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 2  0 299304 236692   8592 1589160    1    4   109   168  193   38 34 23 42  1
 0  0 299304 236892   8592 1589028    0    0     4     0 8159 10012 17 15 69  0
 0  0 299304 236324   8600 1589076    0    0     0   100 7979 8996  8 14 77  1
 0  0 299304 236412   8600 1589124    0    0     0     0 8269 10878 17 14 69  0
 2  0 299304 236656   8600 1589124    0    0     0     0 7900 9927 16 14 70  0
 0  0 299304 236744   8600 1589084    0    0     0    36 8152 9840 15 16 69  0
 0  0 299304 236480   8600 1589120    0    0     4     0 7903 10060 15 16 69  0

2.结果意义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Procs
r: 等待CPU的线程数目
b: 等待IO而被Blocked的线程数目

Memory
swpd: 虚拟内存的使用(Swap空间的使用),如果大于0,表示你的机器物理内存不足了
free: 空闲内存
buff: 用作buffer的空间
cache: 用作cache的空间

Swap
si: 每秒从磁盘读入虚拟内存的大小,如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉
so: 每秒虚拟内存写入磁盘的大小,如果这个值大于0,同上

IO
bi: 块设备每秒接收的块数量,这里的块设备是指系统上的磁盘等块设备
bo: 块设备每秒发送的块数量,例如我们读取文件,bo就要大于0

System
in: 每秒CPU的中断次数,包括时钟中断
cs: 每秒上下文切换次数,这个值要越小越好,太大了,要考虑调低线程或者进程的数目

CPU
These are percentages of total CPU time.
us: 用户CPU时间
sy: 系统CPU时间,如果太高,表示系统调用时间长,例如是IO操作频繁
id: 空闲CPU时间
wa: 等待IO的CPU时间

3.参考

http://www.thomas-krenn.com/en/wiki/Linux_Performance_Measurements_using_vmstat

JVM内存DUMP参数配置

在JVM出现内存溢出或泄露时,为便于排查和定位,需要JVM的启动上增加相应的参数。主要是GC日志和内存DUMP参数.

1.GC日志

1
-Xloggc:$CATALINA_BASE/logs/gc.log

2.内存DUMP

1
2
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=$CATALINA_BASE/logs/heapDump.log

Linux网卡速度

最近项目的图片服务器从公司的服务器下载图片做裁剪等操作的时候,老是存在超时的问题

1
2
3
4
5
6
7
8
java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method) ~[na:1.7.0_51]
    at java.net.SocketInputStream.read(SocketInputStream.java:152) ~[na:1.7.0_51]
    at java.net.SocketInputStream.read(SocketInputStream.java:122) ~[na:1.7.0_51]
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:273) ~[na:1.7.0_51]
    at java.io.BufferedInputStream.read(BufferedInputStream.java:334) ~[na:1.7.0_51]
    at sun.net.www.MeteredStream.read(MeteredStream.java:134) ~[na:1.7.0_51]
    at java.io.FilterInputStream.read(FilterInputStream.java:133) ~[na:1.7.0_51]

手动wget图片一切正常,但是速度还不如本地机器,于是想看一下服务器的网卡信息。下面用本机作为示例:

1.使用ifconfig找到网卡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
eth0      Link encap:以太网  硬件地址 f0:1f:af:27:58:8d  
          inet 地址:192.168.138.99  广播:192.168.139.255  掩码:255.255.254.0
          inet6 地址: fe80::f21f:afff:fe27:588d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  跃点数:1
          接收数据包:696848 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:334077 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1000 
          接收字节:486532283 (486.5 MB)  发送字节:49164276 (49.1 MB)
          中断:18 

lo        Link encap:本地环回  
          inet 地址:127.0.0.1  掩码:255.0.0.0
          inet6 地址: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  跃点数:1
          接收数据包:14772 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:14772 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:0 
          接收字节:1329005 (1.3 MB)  发送字节:1329005 (1.3 MB)

2.查看网卡是否被识别及型号

1
2
xiaobaoqiu@xiaobaoqiu:~/octopress$ lspci | grep Ethernet
0c:00.0 Ethernet controller: Broadcom Corporation NetXtreme BCM5761 Gigabit Ethernet PCIe (rev 10)

3.使用ethtool工具查看网卡的详细信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
xiaobaoqiu@xiaobaoqiu:~/octopress$ sudo ethtool eth0
[sudo] password for xiaobaoqiu: 
Settings for eth0:
    Supported ports: [ TP ]
    Supported link modes:   10baseT/Half 10baseT/Full 
                            100baseT/Half 100baseT/Full 
                            1000baseT/Half 1000baseT/Full 
    Supported pause frame use: No
    Supports auto-negotiation: Yes
    Advertised link modes:  10baseT/Half 10baseT/Full 
                            100baseT/Half 100baseT/Full 
                            1000baseT/Half 1000baseT/Full 
    Advertised pause frame use: Symmetric
    Advertised auto-negotiation: Yes
    Link partner advertised link modes:  10baseT/Half 10baseT/Full 
                                         100baseT/Half 100baseT/Full 
    Link partner advertised pause frame use: No
    Link partner advertised auto-negotiation: Yes
    Speed: 100Mb/s      #网卡速度
    Duplex: Full        #全双工
    Port: Twisted Pair  #网络类型-双绞线
    PHYAD: 1
    Transceiver: internal
    Auto-negotiation: on
    MDI-X: on
    Supports Wake-on: g
    Wake-on: g          #唤醒起用(远程关机开机需设置)
    Current message level: 0x000000ff (255)
                   drv probe link timer ifdown ifup rx_err tx_err
    Link detected: yes  #链路检测

4.查看网卡的连接状态

1
2
xiaobaoqiu@xiaobaoqiu:~/octopress$ sudo mii-tool eth0
eth0: negotiated 100baseTx-FD, link ok

5.网卡数据包收发统计

1
2
3
4
5
6
7
8
9
10
11
12
xiaobaoqiu@xiaobaoqiu:~/octopress$ sudo ethtool -S eth0
NIC statistics:
     rx_octets: 494545915
     rx_fragments: 0
     rx_ucast_packets: 437748
     rx_mcast_packets: 147474
     rx_bcast_packets: 128799
     rx_fcs_errors: 0
     rx_align_errors: 0
     rx_xon_pause_rcvd: 0
     rx_xoff_pause_rcvd: 0
     ...

How to Read Files Quickly

Java中有很多读写文件或者网络流的方法,特别是Java7中加入了AIO之后,可选择的方法更多,本文的目的是想比较一下各种方式的优劣。

本文基本是参考这篇英文:http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quikcly

1.方法List

这里涉及的读文件的方法包括:

1.1 FileInputStreamOneByte

1
2
3
4
5
6
7
8
9
10
@Override
public long doRead() throws IOException {
    long checkSum = 0L;
    FileInputStream fis = new FileInputStream(filePath);
    int b;
    while ((b = fis.read()) != -1)
        checkSum += b;
    Closeables.close(fis, false);
    return checkSum;
}

1.2 FileInputStreamBytes

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
    public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        byte[] array = new byte[BUF_SIZE];
        int nRead;
        while ((nRead = fis.read(array, 0, BUF_SIZE)) != -1) {
            for (int i = 0; i < nRead; i++)
                checkSum += array[i];
        }
        Closeables.close(fis, false);
        return checkSum;
    }

1.3 BufferedInputStreamOneByte

1
2
3
4
5
6
7
8
9
10
@Override
    public long doRead() throws IOException {
        long checkSum = 0L;
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath), BUF_SIZE);
        int b;
        while ((b = bis.read()) != -1)
            checkSum += b;
        Closeables.close(bis, false);
        return checkSum;
    }

1.4 BufferedInputStreamBytes

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
    public long doRead() throws IOException {
        long checkSum = 0L;
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath), BUF_SIZE);
        byte[] array = new byte[BUF_SIZE];
        int nRead;
        while ((nRead = bis.read(array, 0, BUF_SIZE)) != -1) {
            for (int i = 0; i < nRead; i++)
                checkSum += array[i];
        }
        Closeables.close(bis, false);
        return checkSum;
    }

1.5 RandomAccessOneByte

1
2
3
4
5
6
7
8
9
10
public long doRead() throws IOException {
        long checkSum = 0L;
        RandomAccessFile raf = new RandomAccessFile(filePath, READ_MODE);
        int b;
        while ((b = raf.read()) != -1) {
            checkSum += b;
        }
        Closeables.close(raf, false);
        return checkSum;
    }

1.6 RandomAccessBytes

1
2
3
4
5
6
7
8
9
10
11
12
public long doRead() throws IOException {
        long checkSum = 0L;
        RandomAccessFile raf = new RandomAccessFile(filePath, READ_MODE);
        byte[] array = new byte[BUF_SIZE];
        int nRead;
        while ((nRead = raf.read(array, 0, BUF_SIZE)) != -1) {
            for (int i = 0; i < nRead; i++)
                checkSum += array[i];
        }
        Closeables.close(raf, false);
        return checkSum;
    }

1.7 FileChannelByteBufferOneByte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        FileChannel ch = fis.getChannel();
        ByteBuffer bb = ByteBuffer.allocate(BUF_SIZE);
        int nRead;
        while ((nRead = ch.read(bb)) != -1) {
            if (nRead == 0)
                continue;
            bb.position(0);
            bb.limit(nRead);
            while (bb.hasRemaining())
                checkSum += bb.get(); // 从ByteBuffer读一个字节
            bb.clear();
        }
        Closeables.close(fis, false);
        return checkSum;
    }

1.8 FileChannelByteBufferBytes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        FileChannel ch = fis.getChannel();
        ByteBuffer bb = ByteBuffer.allocate(BIG_BUF_SIZE);
        byte[] array = new byte[BUF_SIZE];
        int nRead, nGet;
        while ((nRead = ch.read(bb)) != -1) {
            if (nRead == 0)
                continue;
            bb.position(0);
            bb.limit(nRead);
            while (bb.hasRemaining()) {
                nGet = Math.min(bb.remaining(), BUF_SIZE);
                bb.get(array, 0, nGet);
                for (int i = 0; i < nGet; i++)
                    checkSum += array[i];
            }
            bb.clear();
        }
        Closeables.close(fis, false);
        return checkSum;
    }

1.9 FileChannelByteBufferWrap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        FileChannel ch = fis.getChannel();
        byte[] barray = new byte[BUF_SIZE];
        ByteBuffer bb = ByteBuffer.wrap(barray); // ByteBuffer包装本地array
        int nRead;
        while ((nRead = ch.read(bb)) != -1) {
            for (int i = 0; i < nRead; i++)
                checkSum += barray[i];
            bb.clear();
        }
        Closeables.close(fis, false);
        return checkSum;
    }

1.10 FileChannelMappedByteBufferOneByte

1
2
3
4
5
6
7
8
9
10
public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        FileChannel ch = fis.getChannel();
        MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0L, ch.size());
        while (mb.hasRemaining())
            checkSum += mb.get();
        Closeables.close(fis, false);
        return checkSum;
    }

1.11 FileChannelMappedByteBufferBytes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        FileChannel ch = fis.getChannel();
        MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0L, ch.size());
        byte[] barray = new byte[BUF_SIZE];
        int nGet;
        while (mb.hasRemaining()) {
            nGet = Math.min(mb.remaining(), BUF_SIZE);
            mb.get(barray, 0, nGet);
            for (int i = 0; i < nGet; i++)
                checkSum += barray[i];
        }
        Closeables.close(fis, false);
        return checkSum;
    }

1.12 FileChannelDirectByteBufferOneByte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        FileChannel ch = fis.getChannel();
        ByteBuffer bb = ByteBuffer.allocateDirect(BUF_SIZE);
        int nRead;
        while ((nRead = ch.read(bb)) != -1) {
            bb.position(0);
            bb.limit(nRead);
            while (bb.hasRemaining())
                checkSum += bb.get();
            bb.clear();
        }
        Closeables.close(fis, false);
        return checkSum;
    }

1.13 FileChannelDirectByteBufferBytes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public long doRead() throws IOException {
        long checkSum = 0L;
        FileInputStream fis = new FileInputStream(filePath);
        FileChannel ch = fis.getChannel();
        ByteBuffer bb = ByteBuffer.allocateDirect(BIG_BUF_SIZE);
        byte[] barray = new byte[BUF_SIZE];
        int nRead, nGet;
        while ((nRead = ch.read(bb)) != -1) {
            if (nRead == 0)
                continue;
            bb.position(0);
            bb.limit(nRead);
            while (bb.hasRemaining()) {
                nGet = Math.min(bb.remaining(), BUF_SIZE);
                bb.get(barray, 0, nGet);
                for (int i = 0; i < nGet; i++)
                    checkSum += barray[i];
            }
            bb.clear();
        }
        Closeables.close(fis, false);
        return checkSum;
    }

2.测试

测试文件的大小为83M:

1
2
xiaobaoqiu@xiaobaoqiu:~/Documents/TestData$ ll -h BXBooks.sql
-rw------- 1 xiaobaoqiu xiaobaoqiu 83M 10月  8  2004 BXBooks.sql

3.结论

得到测试数据之后,为了直观展示代码的速度,用ECharts展示,对应的js代码如下(可以在http://echarts.baidu.com/doc/example/line1.html#helianthus%E4%B8%AD%E4%BD%BF%E7%94%A8):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
option = {
    title : {
        text: 'how_to_read_file_quickly',
        subtext: 'baoqiu.xiao'
    },
    tooltip : {
        trigger: 'axis'
    },
    legend: {
        data:['FileInputStreamOneByte','FileInputStreamBytes','BufferedInputStreamOneByte','BufferedInputStreamBytes','RandomAccessOneByte','RandomAccessBytes','FileChannelByteBufferOneByte','FileChannelByteBufferBytes','FileChannelByteBufferWrap','FileChannelMappedByteBufferOneByte','FileChannelMappedByteBufferBytes','FileChannelDirectByteBufferOneByte','FileChannelDirectByteBufferBytes']
    },
    dataZoom : {
        show : true,
        realtime: true,
        start : 0,
        end : 30
    },
    toolbox: {
        show : true,
        feature : {
            saveAsImage : {show: true}
        }
    },
    calculable : true,
    xAxis : [
        {
            type : 'category',
            boundaryGap : false,
            data : ['1','2','4','8','16','32','64','128','256','512','1K','2K','4K','8K','16K','32K','64K','128K']
        }
    ],
    yAxis : [
        {
            type : 'value',
            axisLabel : {
                formatter: '{value} 毫秒'
            }
        }
    ],
    series : [
        {
            name:'FileInputStreamOneByte',
            type:'line',
            data:[29119,28353,27872,27950,32035,40377,34904,36804,36835,33177,32252,37362,32359,31892,32621,32312,32943,33369]
        },
        {
            name:'FileInputStreamBytes',
            type:'line',
            data:[38182,20208,10194,4768,2616,1551,645,471,262,183,150,100,118,125,96,83,124,110]
        },
        {
            name:'BufferedInputStreamOneByte',
            type:'line',
            data:[33404,16966,8613,4718,2525,1491,980,728,677,681,558,608,557,615,505,606,656,693]
        },
        {
            name:'BufferedInputStreamBytes',
            type:'line',
            data:[33880,17333,8487,4851,2293,1632,627,358,242,147,129,113,89,92,107,88,100,95]
        },
        {
            name:'RandomAccessOneByte',
            type:'line',
            data:[28430,27445,26794,27053,28929,28633,29509,28870,28195,27376,28236,27444,28061,28889,27423,28064,28481,28084]
        },
        {
            name:'RandomAccessBytes',
            type:'line',
            data:[31497,16162,8135,4365,2131,1117,561,321,193,146,110,101,109,87,89,91,102,96]
        },
        {
            name:'FileChannelByteBufferOneByte',
            type:'line',
            data:[38778,18325,9447,5344,2430,1413,779,507,380,310,298,259,267,263,249,264,260,258]
        },
        {
            name:'FileChannelByteBufferBytes',
            type:'line',
            data:[19279,9823,5090,2605,1407,854,577,380,333,272,272,239,237,241,237,234,249,270]
        },
        {
            name:'FileChannelByteBufferWrap',
            type:'line',
            data:[38382,17636,9094,4608,2327,1198,646,355,249,151,108,100,92,90,88,103,85,92]
        },
        {
            name:'FileChannelMappedByteBufferOneByte',
            type:'line',
            data:[913,240,92,83,82,87,85,88,83,94,87,90,81,124,81,84,83,120]
        },
        {
            name:'FileChannelMappedByteBufferBytes',
            type:'line',
            data:[731,447,305,332,225,164,139,110,98,88,87,140,97,86,93,92,92,92]
        },
        {
            name:'FileChannelDirectByteBufferOneByte',
            type:'line',
            data:[31287,14473,7296,3815,1919,1001,547,319,200,135,109,98,84,77,80,82,77,86]
        },
        {
            name:'FileChannelDirectByteBufferBytes',
            type:'line',
            data:[14945,8060,4107,2174,1120,580,334,206,149,110,96,95,79,89,81,81,86,84]
        }       
    ]
};

整体展示图如下:

3.1 最快的三种方法

为了展示更细节的地方,设置了y区间范围,在yAxis上设置min和max属性:

1
2
3
4
5
6
7
8
9
10
yAxis : [
        {
            type : 'value',
            min:0,
            max:200,
            axisLabel : {
                formatter: '{value} 毫秒'
            }
        }
    ],

得到如下展示图:

从上面这个图可以大致看出,最快的三种方法(PS,这里只做了一次实验,不是多次实验的平均值,所有数据可能不一定准确):

1.FileChannelMappedByteBufferBytes
2.FileChannelMappedByteBufferOneByte
3.FileChannelDirectByteBufferBytes

4.解析

下面解析一下代码中之前接触较少的东东。

4.1 RandomAccessFile

支持对文件的随机读取和写入。随机存取文件的行为类似存储在文件系统中的一个大型字节数组。存在指向该隐含数组的光标或索引,称为文件指针。

读取操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机存取文件以读取/写入模式创建,则写入操作也可用;写入操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。

提供了boolean,byte,char, short, int, long, float, double这些基本类型的read和write方法。

4.2 FileChannel

FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。

在使用FileChannel之前,必须先打开它。但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream、OutputStream或RandomAccessFile来获取一个FileChannel实例。

1
2
FileInputStream fis = new FileInputStream(filePath);
FileChannel ch = fis.getChannel();

有时可能需要在FileChannel的某个特定位置进行数据的读/写操作。可以通过调用position()方法获取FileChannel的当前位置。也可以通过调用position(long pos)方法设置FileChannel的当前位置。

FileChannel实例的size()方法将返回该实例所关联文件的大小。

FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。

4.3 ByteBuffer

ByteBuffer知识下一次单独讲。

5.BufferedInputStream的defaultBufferSize

BufferedInputStream默认buffer大小为8K:

1
2
3
public class BufferedInputStream extends FilterInputStream {
    private static int defaultBufferSize = 8192;
}

这个从图上也可以比较直观的看到,在缓存为8K左右的时候,性能最好:

5.参考:

http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly

http://colobu.com/2014/10/20/java-buffer-basic/

AB简单使用

简单熟悉Apache附带的压测工具ab,它非常容易使用,ab可以直接在Web服务器本地发起测试请求。

需要清楚的是,ab进行一切测试的本质都是基于HTTP,所以可以说它是对于Web服务器软件的黑盒性能测试,它获得的一切数据和计算结果,都可以通过HTTP来解释。

本文的ab版本信息:

1
2
3
4
xiaobaoqiu@xiaobaoqiu:~/octopress/source/images/io$ ab -V
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

1.参数

所有的参数及意义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
    -n requests     总请求数目,要访问页面的次数,默认为1
    -c concurrency  同一时刻的并发请求数目,默认1
    -t timelimit    测试进行的最大秒数,内部隐含值为50000,默认无时间限制
    -s timeout      response超时时间,默认30秒
    -b windowsize   TCP buffer的大小,单位是bytes
    -B address      指定发出请求的本地ip地址
    -p postfile     包含待POST的数据的文件,需要设置参数-T
    -u putfile      包含待PUT的数据的文件,需要设置参数-T
    -T content-type POST/PUT 数据的Content-type header信息, 比如.
                    'application/x-www-form-urlencoded'
                    默认是'text/plain'
    -v verbosity    设置显示信息的详细程度,- 
                    4或者更大的值会显示头信息,3或者更大的值可以显示响应代码(200等),2或者更大可以显示警告和其他信息。
    -w              已html表格的形式输出结果
    -i              执行HEAD请求,而不是GET
    -x attributes   设置<table>属性的字符串,此属性被填入<table 这里>
    -y attributes   设置<tr>属性的字符串
    -z attributes   设置<td>或者<th>属性的字符串
    -C attribute    对请求附加一个Cookie行,其典型形式是name=value的一个参数对,  
                    此参数可以重复。
    -H attribute    对请求附加额外的头信息。此参数的典型形式是一个有效的头信息行,其中包含
                    了以冒号分隔的字段和值的对 (如, "Accept-Encoding: zip/zop;8bit")
    -A attribute    对服务器提供BASIC认证信任。用户名和密码由一个:隔开,并以base64编码形
                    式发送。无论服务器是否需要(即, 是否发送了401认证需求代码),此字符串都会被发送。
    -P attribute    对一个中转代理提供BASIC认证信任。用户名和密码由一个:隔开,并以base64
                    编码形式发送。无论服务器是否需要(即, 是否发送了401认证需求代码),此字符串都会被发送。
    -X proxy:port   对请求使用代理服务器
    -V              版本信息
    -k              启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。 
                    默认时,不启用KeepAlive功能Use HTTP KeepAlive feature
    -d              不显示"percentage served within XX [ms] table"的消息.
    -S              Do not show confidence estimators and warnings.
    -q              如果处理的请求数大于150,  
                    ab每处理大约10%或者100个请求时,会在stderr输出一个进度计数。 此-q标记可以抑制这些信息。
    -g filename     Output collected data to gnuplot format file.
    -e filename     产生一个以逗号分隔的(CSV)文件,其中包含了处理每个相应百分比的请求 
                    所需要(从1%到100%)的相应百分比的(以微妙为单位)时间。由于这种格式已经“二进制化”,所以比'gnuplot'格式更有用。
    -r              socket接收错误的时候也不退出
    -h              显示usage信息

2.简单使用及结果解析

就对我的博客进行压测,结果如下,简单加入了一些我的注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
xiaobaoqiu@xiaobaoqiu:~/octopress/source/images/io$ ab -n 10 -c 2 -s 10 http://xiaobaoqiu.github.io/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking xiaobaoqiu.github.io (be patient).....done


Server Software:        GitHub.com
Server Hostname:        xiaobaoqiu.github.io
Server Port:            80

Document Path:          /
Document Length:        287269 bytes

Concurrency Level:      2
Time taken for tests:   20.788 seconds
Complete requests:      10
Failed requests:        0
Write errors:           0
Total transferred:      2877109 bytes
HTML transferred:       2872690 bytes
Requests per second:    0.48 [#/sec] (mean)
Time per request:       4157.564 [ms] (mean)    #每个请求的时间
Time per request:       2078.782 [ms] (mean, across all concurrent requests)
Transfer rate:          135.16 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       59  402 717.5     94    2234
Processing:   362 3674 3112.7   3479    8508
Waiting:       60  164 132.8    100     407
Total:        422 4076 3420.4   3558    8602

Percentage of the requests served within a certain time (ms)
  50%   3558        #50%的请求响应时间小于3558毫秒
  66%   7110
  75%   7312
  80%   8544
  90%   8602
  95%   8602
  98%   8602
  99%   8602
 100%   8602 (longest request)  #请求的最长响应时间为8602毫秒