程序员小白如何学会用 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 积分后可见