程序员小白如何学会用 ab 压测接口(linux)
一、Apache Bench 介绍
首先老样子,介绍下ab是个什么东西
Apache Bench 是 Apache 服务器自带的一个web压力测试工具,简称 ab。
二、Apache Bench 原理
1.初始化
- ab工具首先初始化测试环境,包括解析命令行参数、设置目标的请求url、并发数、总请求等。
2.创建连接
- 根据指定的参数,ab工具会创建多个线程,模拟用户同时访问目标的请求url,同时发起http请求
3.发送请求
- ab工具通过这些并发连接向目标服务器发送http请求,请求的数量由总请求数决定。
- 每个请求可以是简单的GET请求,也可以是复杂的POST请求,具体取决与需求。
4.接收响应
- ab工具接收服务器返回服务器返回的HTTP响应,并且会记录每个响应的状态码、响应时间、传输的数据量等信息
5.统计数据
- 在所有请求完成后,ab工具会统计并计算各种性能指标,包括每秒请求数、平均响应时间、最长和最短响应时间、成功和失败请求数等。
6.输出结果
- 最后,ab工具会将结果输出到控制台,可以进一步分析和参考
三、ab命令具体参数
模拟发送get请求
ab -n 100 -c 10 http://localhost:3001/api/v1/hello
模拟发送post请求
ab -n 10000 -c 1000 -p request.json -v 4 -s 36000 -T application/json -H "Authorization: Bearer xxx" http://localhost:3001/api/v1/saveTask
-n 10000:总共发送10000个请求。
-c 1000:并发数为1000,同时发送的请求数,也称为并发连接数。
-p request.json:指定包含请求体的文件。
-v 1-4表示不同的输出日志等级,1基本信息,4更详细的信息,包括请求和响应的内容。
-T application/json:指定请求体的Content-Type。
-H "Authorization: Bearer xxx":指定自定义的HTTP头部。
-s 配置单次超时时间,默认30s。(这个建议配置时间长一点,以防万一超时中断测试)
-l 忽略内容长度检查(如果每次响应长度不同,ab默认为请求失败)
-m 指定http方法,默认情况下使用GET请求
如何发送form-data请求
ab -n 1 -c 1 -p postdata.txt -v 4 -m POST -T 'multipart/form-data; boundary=123454321' http://localhost:3001/api/v1/asr/file/stream
这里遇到坑了,来跟大家讲下
这个postdata.txt格式必须严谨,不然ab请求则会报非200状态码,以为该请求失败
正常格式应该为:
------WebKitFormBoundaryM1tLdAWapR8WCJSe
Content-Disposition: form-data; name="file"; filename="01-29.mp3"
Content-Type: audio/mpeg
<这里应该为对应文件的二进制>
------WebKitFormBoundaryM1tLdAWapR8WCJSe--<这里应该与开头相对应,不管是啥数据只要对应上即可,数字也行,这里的作用呢是起到一个分界符的概念>
按说这么做已经可以了,but这里有坑,就在于换行符,你手动输入是没有换行符这个概念的,所以ab会报非200错误码,比如参数错误等
这时我的解决方法是用到一段pyhon脚本来生成对应上传文件的postdata.txt
python生成postdata.txt
import os
# 文件路径
mp3_file_path = 'xxx.mp3'
postdata_file_path = 'xxx-postdata.txt'
# 边界
boundary = 'WebKitFormBoundaryM1tLdAWapR8WCJSe'
# 读取 MP3 文件内容
with open(mp3_file_path, 'rb') as mp3_file:
mp3_content = mp3_file.read()
# 生成 multipart/form-data 内容
postdata_content = (
f'--{boundary}\r\n'
f'Content-Disposition: form-data; name="file"; filename="{os.path.basename(mp3_file_path)}"\r\n'
f'Content-Type: audio/mpeg\r\n\r\n'
).encode('utf-8') + mp3_content + f'\r\n--{boundary}--\r\n'.encode('utf-8')
# 写入 postdata.txt 文件
with open(postdata_file_path, 'wb') as postdata_file:
postdata_file.write(postdata_content)
print(f'{postdata_file_path} 文件已生成。')
这么做参数就好了,当然这个postdata.txt名称可以随意
然后用python实现自动化执行,最后查看输出结果记录分析即可
python实现自动化执行
import subprocess
import time
import os
# 定义测试参数
tests = [
{"total": 100, "concurrent": 1},
{"total": 500, "concurrent": 5},
{"total": 1000, "concurrent": 10},
{"total": 2000, "concurrent": 20},
{"total": 4000, "concurrent": 40},
{"total": 6000, "concurrent": 60},
{"total": 8000, "concurrent": 80},
{"total": 10000, "concurrent": 100},
{"total": 20000, "concurrent": 200},
{"total": 30000, "concurrent": 300},
{"total": 40000, "concurrent": 400},
{"total": 50000, "concurrent": 500},
{"total": 60000, "concurrent": 600},
{"total": 80000, "concurrent": 800},
{"total": 100000, "concurrent": 1000}
]
# 目标 URL
url = "http://localhost:3001/api/v1/asr/file/stream"
# 请求体文件
request_body_file = "xxx-postdata.txt"
# HTTP 头部
headers = [
"multipart/form-data; boundary=WebKitFormBoundaryM1tLdAWapR8WCJSe"
]
# 生成 ab 命令
def generate_ab_command(total, concurrent):
command = [
"ab",
"-n", str(total),
"-c", str(concurrent),
"-p", request_body_file,
"-v", "4",
"-s", "360000",
"-l",
"-m", "POST",
"-T", headers[0]
]
command.append(url)
return command
# 执行测试并将结果输出到文件
def run_test(total, concurrent, output_file):
command = generate_ab_command(total, concurrent)
with open(output_file, "w") as f:
f.write(f"Running test with total={total} and concurrent={concurrent}\n")
f.write("="*80 + "\n")
subprocess.run(command, stdout=f, stderr=subprocess.STDOUT)
f.write("\n" + "="*80 + "\n\n")
print(f"Test with total={total} and concurrent={concurrent} completed. Output written to {output_file}")
print(f"Sub-command for total={total} and concurrent={concurrent} executed.")
# 创建输出目录
output_dir = "ab_test_results"
os.makedirs(output_dir, exist_ok=True)
# 按顺序执行每组测试
for test in tests:
# 生成输出文件名
output_file_name = f"{test['total']}-{test['concurrent']}-{os.path.basename(request_body_file)}"
output_file = os.path.join(output_dir, output_file_name)
run_test(test["total"], test["concurrent"], output_file)
print("Waiting for 60 seconds before the next test...")
time.sleep(60)
print("All tests completed.")
动态处理不同请求,并发请求,得到响应重定向对应文件中,每单次请求执行完毕,线程停止60s,以便于服务器恢复到完美状态
四、结果分析
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking example.com (be patient)
Completed 1 requests
Finished 1 requests
Server Software: Apache
Server Hostname: example.com
Server Port: 80
Document Path: /
Document Length: 44 bytes
Concurrency Level: 1
Time taken for tests: 0.123 seconds
Complete requests: 1
Failed requests: 0
Total transferred: 1234 bytes
HTML transferred: 44 bytes
Requests per second: 8.13 [#/sec] (mean)
Time per request: 123.00 [ms] (mean)
Time per request: 123.00 [ms] (mean, across all concurrent requests)
Transfer rate: 9.84 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 2 1.0 2 3
Processing: 5 20 5.0 19 30
Waiting: 4 18 4.5 17 28
Total: 6 22 5.5 21 35
Percentage of the requests served within a certain time (ms)
50% 21
66% 23
75% 25
80% 26
90% 28
95% 30
98% 32
99% 34
100% 35 (longest request)
Server Software: 服务器软件名称。
Server Hostname: 服务器主机名。
Server Port: 服务器端口号。
Document Path: 请求的文档路径。
Document Length: 响应文档的长度。
Concurrency Level: 并发数。
Time taken for tests: 完成所有请求所花费的总时间。
Complete requests: 成功完成的请求数。
Failed requests: 失败的请求数。
Total transferred: 总共传输的数据量。
HTML transferred: 传输的HTML数据量。
Requests per second: 每秒处理的请求数。
Time per request: 每个请求的平均响应时间。
Time per request (mean, across all concurrent requests): 所有并发请求的平均响应时间。
Transfer rate: 数据传输速率。
Connection Times: 连接时间的统计数据,包括最小值、平均值、标准差、中位数和最大值。
Percentage of the requests served within a certain time: 请求在特定时间内完成的百分比。
ok 这就是ab压测的完整过程了 随时欢迎提问
1 打赏
打赏 20 积分后可见
那个,现在有跟简单的东西,比如apifox
阅
大佬
派除我佬
看不懂,感觉很厉害的样子!插眼!
确实很多简单的,但是俺这压测的接口通过堡垒机内网访问进去,没通外网捏~
派除我佬