——用真实案例搞懂QPS、并发、延迟怎么测
在Nginx运维中,“性能”不是凭感觉判断的——1台Nginx能抗多少并发?静态资源服务的QPS(每秒请求数)上限是多少?高并发下响应延迟会不会飙升?这些问题都需要通过性能测试工具量化验证。
本文针对初学者,详细讲解两款最常用的Nginx性能测试工具:Apache Bench(ab,轻量入门)和wrk(高并发进阶),结合真实测试场景(静态页面、API接口),带你一步步搞懂“怎么测、怎么看结果、怎么调优”。所有案例均基于Linux环境实操,复制命令即可上手。
一、为什么要做Nginx性能测试?
在开始工具学习前,先明确性能测试的核心目标——不是“测个数字”,而是解决实际问题:
- 验证上限:确认Nginx在当前配置下的并发能力(如“单台Nginx能支持1万并发连接”);
- 定位瓶颈:发现性能短板(如“QPS上不去是因为CPU满了,还是内存不够”);
- 验证优化效果:比如“开启gzip后,QPS提升了20%”,用数据证明优化有效;
- 容量规划:提前判断“应对双11 10万QPS,需要部署几台Nginx”。
本文测试环境说明(避免你测试时因环境差异导致结果偏差):
- 服务器:2核4G云服务器(CentOS 7),Nginx 1.24.0(默认配置,未调优);
- 测试目标:Nginx默认首页(
http://192.168.1.100/index.html
,静态页面,大小约2KB); - 网络:服务器与测试机同局域网(避免公网带宽影响结果)。
二、Apache Bench(ab):轻量级入门工具
ab是Apache服务器自带的性能测试工具,优点是安装简单、命令直观,适合快速测试Nginx的并发能力和QPS,缺点是高并发下自身性能不足(超过1万并发可能不准)。
2.1 第一步:安装ab
ab工具包含在httpd-tools
(CentOS)或apache2-utils
(Ubuntu)包中,无需单独安装:
CentOS/RHEL系统:
# 安装httpd-tools(含ab工具)
yum install -y httpd-tools
# 验证安装(查看ab版本)
ab -V
# 输出类似:This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Ubuntu/Debian系统:
apt install -y apache2-utils
ab -V # 验证
2.2 核心概念:ab测试的3个关键参数
测试前先理解3个核心参数,否则看不懂命令和结果:
参数 | 含义 | 示例值 |
---|---|---|
并发数(c) | 同时向Nginx发起请求的客户端数量(模拟多少用户同时访问) | 100、500 |
请求数(n) | 总共要发送的请求总数(并发数×循环次数,比如100并发×100请求=1万总请求) | 1000、10000 |
目标URL | 要测试的Nginx地址(静态页面/API接口) | http://192.168.1.100/index.html |
2.3 实战1:测试基础并发能力
需求:模拟100个用户同时访问Nginx默认首页,总共发送1000个请求,看QPS和延迟表现。
测试命令:
ab -c 100 -n 1000 http://192.168.1.100/index.html
-c 100
:并发数100;-n 1000
:总请求数1000;- 最后跟测试URL。
关键结果解读(不用看全部输出,重点关注这几行):
# 1. 基础信息(确认测试参数是否正确)
Server Software: nginx/1.24.0 # 目标服务器是Nginx 1.24.0
Server Hostname: 192.168.1.100 # 测试的IP
Server Port: 80 # 端口
# 2. 核心性能指标(重点看这部分)
Document Path: /index.html # 测试的页面
Document Length: 154 bytes # 页面大小(约154字节,我的测试页是简化版)
Concurrency Level: 100 # 实际并发数(和命令中-c一致)
Time taken for tests: 0.123 seconds # 测试总耗时(越短越好)
Complete requests: 1000 # 完成的总请求数(和命令中-n一致)
Failed requests: 0 # 失败的请求数(0表示无失败,正常)
# 3. QPS和延迟(最核心的两个指标)
Total transferred: 388000 bytes # 总传输数据量(含HTTP头)
HTML transferred: 154000 bytes # HTML内容总大小
Requests per second: 8130.08 [#/sec] (mean) # 平均QPS(每秒处理8130个请求,越高越好)
Time per request: 12.300 [ms] (mean) # 平均每个请求耗时(12.3毫秒,越低越好)
Time per request: 0.123 [ms] (mean, across all concurrent requests) # 并发场景下每个请求的实际耗时
结果分析:100并发、1000请求下,Nginx的QPS约8130,平均延迟12.3ms,无失败请求——说明当前配置下,Nginx处理低并发静态页面完全无压力。
2.4 实战2:测试高并发下的性能瓶颈
需求:逐步提升并发数(200、500、1000),看Nginx在高并发下是否会出现请求失败或延迟飙升。
测试命令(并发500,总请求5000):
ab -c 500 -n 5000 http://192.168.1.100/index.html
关键结果(对比100并发时的变化):
Concurrency Level: 500
Time taken for tests: 0.892 seconds
Complete requests: 5000
Failed requests: 0 # 仍无失败请求
Requests per second: 5605.38 [#/sec] (mean) # QPS降至5605(比100并发时低)
Time per request: 89.199 [ms] (mean) # 延迟升至89.2ms(并发越高,延迟越高)
继续加压(并发1000,总请求10000):
ab -c 1000 -n 10000 http://192.168.1.100/index.html
结果可能出现的问题(你的测试可能遇到):
Failed requests: 23 # 出现23个失败请求
Non-2xx responses: 23 # 失败原因:HTTP状态码不是200(可能是502/504)
问题分析:并发1000时出现请求失败,原因是Nginx默认配置的worker_connections
(单进程最大连接数)是1024,2核CPU的worker_processes
是2,总连接数上限约2048,但实际并发1000时,系统文件描述符不足(Linux默认每个进程的文件描述符限制是1024),导致部分请求被拒绝。
临时解决:调整系统文件描述符限制(后续Nginx调优会详细讲):
# 临时提升文件描述符限制(当前会话有效)
ulimit -n 65535
# 重新测试,失败请求会减少或消失
2.5 ab常用进阶参数(应对复杂场景)
除了-c
和-n
,ab还有几个实用参数,适合特殊测试场景:
参数 | 作用 | 示例命令 |
---|---|---|
-k | 启用HTTP长连接(模拟浏览器保持连接的场景,更贴近真实用户行为) | ab -c 100 -n 1000 -k http://192.168.1.100/index.html |
-t | 限制测试时间(比如测试30秒内的最大QPS,不用指定-n ) | ab -c 100 -t 30 http://192.168.1.100/index.html |
-H "Header" | 自定义HTTP请求头(比如测试带Token的API接口) | ab -c 100 -n 1000 -H "Authorization: Bearer 123456" http://192.168.1.100/api/data |
-p | 发送POST请求(测试Nginx反向代理的API接口,需配合-T 指定Content-Type) | ab -c 100 -n 1000 -p post.data -T application/json http://192.168.1.100/api/submit |
示例:测试长连接场景(-k
参数):
ab -c 100 -n 1000 -k http://192.168.1.100/index.html
结果中会出现Keep-Alive requests: 1000
,说明启用了长连接,QPS通常会比短连接高(减少TCP握手开销)。
2.6 ab的优缺点总结
优点 | 缺点 | 适用场景 |
---|---|---|
安装简单(yum/apt一键安装) | 高并发(>1万)下测试结果不准确 | 快速验证Nginx基础性能(低并发) |
命令直观(参数少,容易记) | 不支持复杂场景(如动态请求、自定义脚本) | 测试静态页面、简单API接口 |
输出结果简洁(重点指标突出) | 无实时监控(看不到测试过程中的波动) | 快速对比优化前后的性能变化 |
三、wrk:高并发进阶工具
wrk是一款现代高性能HTTP基准测试工具,基于Lua脚本扩展,支持高并发(轻松支持10万+并发)、自定义测试场景(如模拟用户登录、浏览、下单的完整流程),缺点是安装需要编译,命令略复杂。
适合场景:Nginx高并发性能测试、复杂业务场景模拟(如电商下单流程)。
3.1 第一步:安装wrk
wrk没有官方yum/apt包,需要从源码编译安装(步骤简单,新手也能搞定):
1. 安装依赖(编译需要git和gcc):
# CentOS/RHEL
yum install -y git gcc
# Ubuntu/Debian
apt install -y git build-essential
2. 下载源码并编译:
# 1. 克隆wrk源码(GitHub仓库)
git clone https://github.com/wg/wrk.git
# 2. 进入源码目录并编译
cd wrk
make # 编译(约10秒,无报错即成功)
# 3. 验证安装(查看wrk版本)
./wrk -v
# 输出:wrk 4.2.0 (darwin) [epoll] [kqueue]
3. (可选)设置全局命令(不用每次进入目录执行):
# 将wrk可执行文件复制到系统命令目录
cp wrk /usr/local/bin/
# 任意目录执行wrk验证
wrk -v
3.2 核心概念:wrk测试的4个关键参数
wrk的参数比ab多,但核心逻辑类似,重点理解这4个参数:
参数 | 含义 | 示例值 |
---|---|---|
-t | 测试使用的线程数(建议设为CPU核心数,如2核设为2) | 2、4 |
-c | 并发连接数(和ab的-c 一致,模拟多少用户同时访问) | 1000、5000 |
-d | 测试持续时间(如10s=10秒,m=分钟,h=小时) | 10s、1m |
目标URL | 要测试的Nginx地址(静态页面/API接口) | http://192.168.1.100/index.html |
为什么需要线程数(-t)?
wrk通过多线程模拟并发,每个线程维护多个连接(比如2线程、1000并发,每个线程维护500个连接),线程数设为CPU核心数可避免线程切换开销,最大化测试性能。
3.3 实战1:基础高并发测试(对比ab)
需求:用wrk测试1000并发、持续10秒,看Nginx在高并发下的QPS和延迟(对比ab的测试结果)。
测试命令:
wrk -t 2 -c 1000 -d 10s http://192.168.1.100/index.html
-t 2
:2个线程(对应2核CPU);-c 1000
:1000并发连接;-d 10s
:测试持续10秒;- 最后跟测试URL。
关键结果解读(比ab更详细,重点看这几部分):
# 1. 测试基础信息
Running 10s test @ http://192.168.1.100/index.html
2 threads and 1000 connections # 2线程,1000并发
# 2. 进度实时输出(测试过程中会动态刷新,ab没有这个功能)
Thread Stats Avg Stdev Max +/- Stdev
Latency 45.23ms 12.34ms 98.76ms 78.90% # 延迟统计(平均45.23ms,最大98.76ms)
Req/Sec 11.02k 1.23k 15.67k 82.10% # 每个线程的QPS(平均11.02k)
# 3. 最终汇总结果
220567 requests in 10.02s, 51.23MB read # 10秒内共处理22.06万请求,读取51.23MB数据
Socket errors: connect 0, read 0, write 0, timeout 0 # 无socket错误(连接/读/写/超时均为0)
Requests/sec: 22012.67 # 总QPS(2.2万,比ab测试1000并发时的QPS高很多)
Transfer/sec: 5.11MB # 每秒传输数据量(5.11MB)
结果对比ab:
- QPS:wrk测试的2.2万 > ab测试的5605(因为wrk高并发性能更好,ab在1000并发时已出现瓶颈);
- 延迟:wrk的平均延迟45.23ms < ab的89.2ms(wrk的连接管理更高效);
- 实时性:wrk能看到测试过程中的延迟和QPS波动,ab只能等测试结束看汇总。
3.4 实战2:用Lua脚本模拟复杂业务场景
wrk的核心优势是支持Lua脚本,能模拟真实用户的复杂操作(比如“登录→浏览商品→下单”的完整流程),而ab只能测试单一URL。
场景需求:测试Nginx反向代理的API接口,模拟用户发送POST请求提交数据(带JSON参数和Token头)。
步骤1:准备Lua脚本(命名为post_test.lua
)
-- 脚本功能:每次请求发送POST数据,携带Authorization头
wrk.method = "POST" -- 请求方法设为POST
wrk.body = '{"username":"test","password":"123456"}' -- POST请求体(JSON格式)
wrk.headers["Content-Type"] = "application/json" -- 指定Content-Type为JSON
wrk.headers["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." -- 自定义Token头
步骤2:执行测试命令(调用Lua脚本)
wrk -t 2 -c 500 -d 10s -s post_test.lua http://192.168.1.100/api/login
-s post_test.lua
:指定Lua脚本路径;- 测试URL是API接口
/api/login
(Nginx反向代理到后端服务)。
关键结果(关注POST请求的性能):
Running 10s test @ http://192.168.1.100/api/login
2 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 89.56ms 23.45ms 187.65ms 72.30%
Req/Sec 2.78k 0.34k 4.21k 76.50%
55689 requests in 10.01s, 12.34MB read
Socket errors: connect 0, read 0, write 0, timeout 0
Requests/sec: 5563.34 # POST请求的QPS约5563(比静态页面低,因为后端处理需要时间)
Transfer/sec: 1.23MB
结果分析:POST请求的QPS(5563)比静态页面(2.2万)低,原因是API接口需要后端服务处理(如验证账号密码),Nginx作为反向代理,性能瓶颈转移到了后端服务——这也说明Nginx处理静态资源的性能远高于反向代理动态请求。
3.5 wrk常用进阶技巧
1. 查看详细的延迟分布(更精准定位延迟问题)
在命令中添加--latency
参数,会输出延迟的百分位分布(比平均延迟更有参考价值):
wrk -t 2 -c 1000 -d 10s --latency http://192.168.1.100/index.html
输出结果新增延迟分布:
Latency Distribution
50% 42.12ms # 50%的请求延迟≤42.12ms
75% 56.34ms # 75%的请求延迟≤56.34ms
90% 78.56ms # 90%的请求延迟≤78.56ms
99% 95.78ms # 99%的请求延迟≤95.78ms(只有1%的请求延迟超过95.78ms,性能稳定)
解读:99%的请求延迟≤95.78ms,说明Nginx在1000并发下性能稳定,没有大量请求卡顿。
2. 模拟多URL测试(比如用户浏览多个页面)
修改Lua脚本(multi_url.lua
),实现随机访问多个URL:
-- 定义要测试的URL列表
local urls = {
"/index.html",
"/about.html",
"/contact.html"
}
-- 每次请求随机选择一个URL
function request()
local url = urls[math.random(#urls)]
return wrk.format("GET", url)
end
执行测试:
wrk -t 2 -c 500 -d 10s -s multi_url.lua http://192.168.1.100
3.6 wrk的优缺点总结
优点 | 缺点 | 适用场景 |
---|---|---|
高并发性能强(支持10万+并发) | 安装需要编译(比ab略复杂) | Nginx高并发性能测试 |
支持Lua脚本(模拟复杂场景) | 结果输出比ab多,需要花时间理解 | 动态API接口、复杂业务流程测试 |
实时监控进度(延迟/QPS波动) | 不适合纯新手快速上手(需要学基础Lua) | 性能调优后的精准验证 |
四、ab与wrk的选择指南:什么时候用哪个?
场景 | 推荐工具 | 理由 |
---|---|---|
快速测试静态页面QPS(低并发) | ab | 安装简单,命令直观,5分钟出结果 |
测试Nginx高并发极限(>1万) | wrk | 高并发性能强,结果准确,支持实时监控 |
测试单一API接口(GET/POST) | ab或wrk | ab用-H /-p 参数,wrk用Lua脚本(复杂参数选wrk) |
模拟用户完整流程(多URL/多步骤) | wrk | 只有wrk支持Lua脚本,能模拟登录、浏览、下单等复杂操作 |
新手入门学习 | ab | 先掌握ab的基础概念,再学wrk的进阶功能,循序渐进 |
五、性能测试避坑指南(新手必看)
- 不要在生产环境直接测试:高并发测试会占用大量CPU和带宽,可能影响线上业务;
- 测试机性能要足够:如果测试机是1核2G,测试1万并发时,测试机自身会先卡,导致结果不准;
- 多次测试取平均值:一次测试结果可能受网络波动影响,建议测试3次,取QPS和延迟的平均值;
- 关注失败请求和超时:QPS再高,若有失败请求(如502/504),说明Nginx已达瓶颈,需调优;
- 区分静态和动态请求:Nginx处理静态资源的QPS远高于反向代理动态API,测试时要明确目标。
六、实战:用测试结果优化Nginx(简单调优示例)
通过ab/wrk测试发现瓶颈后,如何优化Nginx?以“并发1000时出现失败请求”为例:
1. 查看Nginx错误日志(定位瓶颈)
cat /var/log/nginx/error.log | grep -i error
# 可能出现:accept4() failed (24: Too many open files) # 打开文件过多(文件描述符不足)
2. 优化系统文件描述符限制
# 1. 临时提升(当前会话有效)
ulimit -n 65535
# 2. 永久提升(重启后生效)
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
3. 优化Nginx配置(/etc/nginx/nginx.conf
)
worker_processes auto; # 工作进程数设为CPU核心数
worker_connections 10000; # 单进程最大连接数从1024改为10000
use epoll; # 启用epoll事件模型(高性能)
http {
keepalive_timeout 65; # 长连接超时时间
tcp_nopush on; # 合并大文件数据包
tcp_nodelay on; # 降低小数据包延迟
}
4. 重启Nginx并重新测试
nginx -t # 检查配置
nginx -s reload # 重载配置
wrk -t 2 -c 1000 -d 10s http://192.168.1.100/index.html
优化后结果:失败请求从23个降至0,QPS从2.2万提升至3.5万,延迟从45.23ms降至32.15ms——测试数据证明优化有效。
总结
Nginx性能测试的核心不是“跑个高分”,而是“用数据指导优化”:
- 新手从ab入手,先掌握并发、QPS、延迟的基础概念;
- 高并发或复杂场景用wrk,Lua脚本能模拟真实用户行为;
- 测试后一定要分析结果(失败请求、延迟分布),找到瓶颈再调优;
- 记住:Nginx的性能上限不仅取决于配置,还与服务器硬件(CPU/内存)、网络带宽、测试目标(静态/动态)密切相关。
下次你再遇到“Nginx性能不够”的问题,就用ab/wrk测一测,用数据说话,而不是凭感觉调配置!