程序员小白如何学会用 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
阅
大佬
派除我佬
看不懂,感觉很厉害的样子!插眼!
确实很多简单的,但是俺这压测的接口通过堡垒机内网访问进去,没通外网捏~
派除我佬