本文简要介绍Apache ab(ApacheBench),一个性能基准工具。

Apache ab官方网址在这里

1 Apache ab是什么

Apache ab原本是一款为了对Apache HTTP server进行基准测试而实现的工具。它的目的是让用户快速确认目标Apache HTTP server的性能,例如测试出QPS等性能指标。

因为Apache ab发出的是标准HTTP请求,所以使用ab也可以对Nginx、Tomcat、Jetty等HTTP server进行性能测试。

1.1 安装ab

Mac

Mac默认已经安装了Apache ab。可以在终端输入如下命令验证:

ab -V

如果输出类似如下内容,则证明Apache ab已在Mac上安装:

apache-ab-v

Windows

在Windows上安装Apache ab的步骤相对复杂一些,因为Apache并未提供针对Windows的安装包。一般我们可以使用第三方提供的Windows环境下的Apache安装包。

首先进入Apache HTTP Server的下载页面,如下:

apache-homepage

点击上图红框中的链接,进入Apache针对Windows系统的说明页面,如下:

apache-windows

一般选择Apache Lounge,进入如下页面:

apache-apachelounge

然后选择对应的Windows版本下载即可。下载完成后解压ZIP包,可以在bin目录下找到ab.exe。这个就是在Windows环境下可执行的ab工具。

apache-windows-ab

1.2 快速体验

Apache ab命令很简单,例如我们使用2个并发一共访问example.org网站10次,命令如下:

ab -n 10 -c 2 https://example.org/

返回结果如下所示:

apache-ab-result

2 Apache ab参数

Apache ab命令的可用参数说明如下:

参数 说明
-A 向服务器提供 BASIC 身份验证凭证。用户名和密码用一个": “分隔,并以 base64 编码发送。无论服务器是否需要(即已发送 401 身份验证请求),都会发送该字符串。
-b TCP 发送/接收缓冲区的大小(字节)。
-B 对外连接时绑定的地址。
-c 请求并发数,即一次执行多个请求的数量。默认为一次一个请求。
-C 在请求中添加 Cookie: 一行。参数通常以 name=value 对的形式出现。该字段可重复使用。
-d 不显示 “XX [ms] 表内送达百分比”。
-e 输出一个CSV(逗号分隔值)文件,其中包含每个百分比(从 1%到 100%)的请求处理时间(以毫秒为单位)。
-E 连接到SSL网站时,使用提供的PEM格式客户证书与服务器进行身份验证。该文件应包含客户端证书、中间证书和私钥。(适用于Apache HTTP server 2.4.36及更高版本)
-f 指定SSL/TLS协议(SSL2、SSL3、TLS1、TLS1.1、TLS1.2 或 ALL)。(2.4.4及更高版本支持TLS1.1和TLS1.2)
-g 将测试结果输出成"gnuplot"或TSV(Tab单独值)文件。该类型文件可使用Gnuplot、IDL、Mathematica、Igor甚至Excel等软件打开。标签位于文件的第一行。
-h 显示使用信息。
-H 向HTTP请求附加额外的Header信息。参数的形式通常是有效的标头行,包含以冒号分隔的field-value对(例如,“Accept-Encoding: zip/zop;8bit”)。
-i 用HEAD请求代替GET请求。
-k 启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。默认不启用。
-l 如果HTTP response的长度不固定,也不会报错。这个参数在动态页面中很有用。适用于Apache HTTP server 2.4.7及更高版本。
-m 自定义HTTP请求的方法。适用于Apache HTTP server 2.4.10及更高版本。
-n 指定压测期间的请求次数总数。默认只执行一次请求。
-p 指定POST请求所要包含的数据文件。需要与-T参数配合使用。
-P 向代理提供BASIC验证凭据。用户名和密码以单个”: “分隔,并以base64编码发送。无论代理是否需要(即已发送407代理验证需求),都会发送该字符串。
-q 默认情况下,ab设定的请求次数(-n)超过150个时,会每隔10%或大约100个请求后输出进度计数。使用-q可以取消这些信息。
-r 当Socket收到错误时不退出。
-s 设置Socket的超时时间,单位是秒。默认为30秒。适用于Apache HTTP server 2.4.4及更高版本。
-S 不显示中位数和标准偏差值,当平均值和中位数相差超过标准偏差的一或两倍时,也不显示警告/错误信息。默认为最小值/最大值/最大值。
-t 用于设定ab基准测试的时长。使用它可以在固定的总时间内对服务器进行基准测试。默认情况下没有时间限制。
-T 用于设定POST/PUT请求的Content-type信息,例如:application/x-www-form-urlencoded。默认为 text/plain。
-u 指定PUT请求所要包含的数据文件。需要与-T参数配合使用。
-v 设置verbosity级别 - 4及以上级别打印标题信息,3及以上级别打印响应代码(404、200 等),2及以上级别打印警告和信息。
-V 显示Apache ab的版本信息。
-w 以HTML table形式打印结果。默认表格为两列宽,白色背景。
-x 用作<table>属性的字符串。属性插入<table here>。
-X 使用代理服务器处理请求。
-y 用作<tr>属性的字符串。
-z 用作<td>属性的字符串。
-Z 指定SSL/TLS密码套件。(具体请查阅openssl相关内容)

3 Apache ab结果说明

Apache ab的返回结果,说明如下:

参数 说明
Server Software 第一个成功的response头中返回的值(如果有)。这包括头中从开始到检测到十进制值为32的字符(最明显的是空格或 CR/LF)为止的所有字符。
Server Hostname 命令行中给出的DNS或IP地址。
Server Port Apache ab连接的端口。如果命令行中没有指定端口,则http默认端口为80,https默认端口为443。
SSL/TLS Protocol 客户端和服务器之间协商的协议参数。只有使用SSL时才会打印。
Document Path 从命令行字符串中解析出的请求URI。
Document Length 这是第一个成功返回的文档的大小(以字节为单位)。如果文档长度在测试过程中发生变化,response将被视为错误。
Concurrency Level 测试期间使用的并发客户端数量。
Time taken for tests Apache ab测试的总体时间,即从创建第一个连接开始到收到最后一个response所用的时间。
Complete requests 收到的成功回复数量。
Failed requests 失败的请求数量。如果该数字大于0,则将打印另一行,显示因连接、读取、内容长度不正确或异常而失败的请求数。
Write errors 写入失败的错误次数。
Non-2xx responses 不是200系列HTTP Code的response数量。如果所有回复都是200,则不打印此信息。
Keep-Alive requests 发出Keep-Alive请求的连接数量。
Total body sent 如果测试中有发送数据,则这是测试期间发送的字节总数。如果测试中未发送数据,则省略此字段。
Total transferred 从服务器接收到的字节总数。这个数字基本上就是通过线路发送的字节数。
HTML transferred 从服务器接收到的文档字节总数。该数字不包括HTTP头信息中的字节数。
Requests per second 这是每秒的请求数,即QPS。该值是请求数除以总耗时的结果。
Time per request 所有HTTP请求花费的平均时间,即RT。第一个值的计算公式为并发量 * 时间 * 1000 / 请求次数,第二个值的计算公式为时间 * 1000 / 请求次数。
Transfer rate 传输速率(kb/s),计算公式为总读取次数/1024 次/所用时间。

3.1 重要的性能指标

指标参数 说明
Requests per second 这是衡量服务器性能最重要的指标。它表示了服务器指定接口的吞吐量。
Time per request 这是衡量指定接口的重要指标。它表示了该接口一次请求的平均耗时。
Transfer rate 这是衡量服务器出口网络的重要指标。它可以用来评估服务器出口带宽是否到达瓶颈。对于response body很大的接口,该指标很有参考价值。
Percentage of the requests served within a certain time (ms) 这是压测过程中请求耗时的分布情况。这个指标对于服务器稳定性有参考价值。如果波动较大、较频繁,则需要关注服务器稳定性。

4 常见的场景

4.1 带Cookie的Get请求

Apache ab命令如下:

ab -n 100000 -c 10  -C 'cName=cValue' http://localhost:8888/cookieget

以上使用HTTP GET方法请求http://localhost:8888/cookieget接口100000次,请求并发量是10。每个请求的头部带了一个Cookie,即cName=cValue。该接口的实现样例(使用SpringBoot框架)如下:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@RestController
public class CookieGetController {

	@GetMapping("/cookieget")
	public String cookieGet(HttpServletRequest request, HttpServletResponse response) {
		/**
		 * 读取Cookies
		 */
		Cookie cookies[] = request.getCookies();
		for (Cookie cookie : cookies) {
			/**
			 * 循环打印Cookie内容
			 */
			System.out.println(cookie.getName() + "=" + cookie.getValue());
		}

		return "OK";
	}

}

执行结果如下图所示:

ab-get-cookie

4.2 指定数据格式的POST请求

Apache ab命令如下:

ab -n 100000 -c 10  -p './pJson.txt' -T 'application/json;charset=utf-8' http://localhost:8888/abPost

以上使用HTTP POST方法请求http://localhost:8888/abPost接口100000次,请求并发量是10。每个请求提交了一个Post数据,即pJson.txt。该文件内容如下:

{
  "a": "A"
}

该接口的实现样例(使用SpringBoot框架)如下:

import java.util.Random;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AbPostController {

	@PostMapping("/abPost")
	public String abPost(@RequestBody AbPostBody abPostBody) throws InterruptedException {
		System.out.println("a=" + abPostBody.getA());

		Thread.sleep(random.nextLong(100L, 500L));
		
		return "OK";
	}

	/**
	 * attribute(s)
	 */
	private static Random random = new Random();
}

class AbPostBody {
	/**
	 * getters & setters
	 */
	public String getA() {
		return a;
	}

	public void setA(String a) {
		this.a = a;
	}

	/**
	 * attribute(s)
	 */
	private String a;
}

执行结果如下图所示:

ab-post-body