☰
性能调优必知:吞吐量、QPS、并发数与响应时间全解析
2026/10/16 5:02:59 网站建设 项目流程

你有没有遇到过这种情况:线上接口平时响应挺快,一到流量高峰直接卡死;运维把线程池调大,速度反而更慢;加了几台机器,QPS却没什么变化。我刚开始接触性能调优时,也以为只要背住“QPS=并发数/响应时间”就够了,直到某次压测才发现,系统吞吐量、QPS、并发数、响应时间这四件事,单独拿出来谁都能说两句,合在一起却经常被误用。这篇文章我想从一个实际做性能调优的视角,把这几个指标的定义、关系、测量方式和提升思路一次讲清楚,如果你正在排查系统慢、压测上不去容量、或者准备写性能调优方案,应该能少走不少弯路。

1. 先把四个指标摆在桌面上:定义、口径与常见误区

1.1 吞吐量:系统真正完成的工作量

吞吐量(Throughput)是单位时间内系统成功处理并返回结果的业务总量,常见口径有每秒请求数、每秒事务数、每秒处理消息数、每分钟订单数等。它回答的问题是“这台系统在单位时间里能产出多少有效结果”。

但这里有一个容易被忽略的点:吞吐量强调的是“完成”,不只是“接收”。压测时经常出现“系统每秒接收了几千个请求,但真正成功返回的只有一半”,这时候要说吞吐量是失败的那几百,而不是接收量。很多人喜欢盯着网关的入向流量看,觉得每秒进来多少请求就是系统能扛多少,那是“输入速率”,不是系统的吞吐量。相当于是快递站门口运来多少包裹,跟快递站实际分拣完多少包裹,是两回事。

我在实际统计里会明确把“成功率100%”作为吞吐量统计前提:失败请求不计入,重试导致的重复请求也不计入。否则数字会很好看,但业务指标并没有变好。

1.2 QPS、TPS、RPS:口径决定了结论

QPS(Queries Per Second)最初偏查询场景,TPS(Transactions Per Second)偏事务场景,RPS(Requests Per Second)是更通用的请求口径。这三个词在日常讨论里经常混用,但含义差别很大:

  • QPS:每秒查询数,适合读多写少的接口,比如商品详情、用户信息查询;
  • TPS:每秒事务数,一个事务可能包含多个请求,比如下单会包含创建订单、扣库存、支付回调等多个动作;
  • RPS:每秒请求数,更多是偏网络层的请求计量,一个请求哪怕只是网关转发失败,也会被统计进去。

重要的不是用哪个词,而是团队里必须统一口径。我之前在某个跨平台系统的压测报告里见过“QPS 5000”和“TPS 5000”被放在同一张对比表里,实际上前者统计的是网关转发的全部HTTP请求,后者统计的是业务系统里成功提交的事务,差了不止一个量级,结论完全没法用。所以每次压测前先问一句:这个指标是在哪一层、用什么条件统计的?是到网关了,到应用了,还是到数据库了?

1.3 并发数:在途请求才是真并发

并发数不等于在线用户数。在线用户可能同时有1万人,但绝大多数人停留在页面上发呆、读文章、犹豫要不要下单,真正到达系统的并发请求可能只有几十到几百。并发数也不是线程数、连接数。它描述的是“处于处理中状态”的请求数量:一个请求从进入系统到返回响应,这段时间里它占用一些处理资源,所有“在途请求”加在一起,就是并发数。

可以把并发数再拆成三种状态:正在CPU上执行的、正在等待IO或锁的、正在排队等待调度的。后面两种是性能瓶颈的主要来源。很多系统CPU利用率不高但响应时间很差,就是因为大量线程阻塞在等待数据库连接、等待网络返回、等待锁释放,表面上“系统很空”,实际请求全在排队。

1.4 响应时间:不要只盯平均值

响应时间(Response Time,RT)是从客户端发出请求到收到响应的时间,包括网络传输、排队等待、业务处理、序列化和反序列化等。只看平均值会骗人:某接口平均RT是100ms,看起来不错,但P99可能是2秒,意味着每100个请求里就有一个“卡住”的,这部分用户感知到的就是系统很慢。

我一般关注三个值:平均RT看整体趋势,P95/P99看绝大多数请求的真实体验,最大RT看偶发超时来源。性能调优的目标不是把平均RT压到最低,而是让P99稳定在可接受范围。比如业务要求300ms内返回,那就盯着P95不超过300ms、P99不超过500ms,比一味压缩平均值更有意义。

指标常见口径常见误区
吞吐量单位时间成功完成的业务量把接收量当成完成量
QPS/TPS/RPS每秒请求数/事务数不同层级口径混用
并发数在途处理中的请求数等于在线用户数或线程数
响应时间请求发出到收到响应的时间只看平均值,忽略P99

2. 四者的数学关系与实际计算:调优的起点不是感觉,是等式

2.1 利特尔法则:并发数 = QPS × 响应时间

排队论里的利特尔法则(Little's Law)在稳定系统中成立:系统里平均在途请求数,等于请求到达率乘以平均停留时间。换成性能指标就是:

并发数 = QPS × 平均响应时间 QPS = 并发数 / 平均响应时间

这个等式非常实用。举个例子:某接口QPS是1000,平均RT是100ms,那么系统里平均同时在处理的请求数就是 1000 × 0.1 = 100。如果这个系统的处理能力上限只有80并发,那当到达的并发需求超过80时,响应时间就会开始恶化。

我之前给某个读多写少的业务系统做容量评估时,先拿压测工具测出单实例当前支撑的QPS和RT,然后用这个公式推算目标QPS下需要的并发数,再判断现有线程池和连接池配置够不够。这样做比凭感觉去调线程池要靠谱得多,至少在动配置之前,心里先有一笔账。

2.2 吞吐量和响应时间之间不是线性关系

当系统处于低负载区,吞吐量会随着并发数上升而上升,响应时间基本平稳;当并发数超过某个阈值,系统进入拐点区,吞吐量不再上升甚至下降,响应时间开始明显拉长。这个拐点通常就是系统当前真正的容量上限。

很多人的直觉是“并发数越大,吞吐量越大”,实际上超过拐点后,线程上下文切换、锁竞争、内存垃圾回收、连接等待这些副作用,会让吞吐量不升反降。可以说,吞吐量和响应时间是互相牵制的:在同一份资源配置下,把吞吐量压到极限附近,要么牺牲响应时间换取少量额外吞吐,要么吞吐量直接掉头向下。所以判断系统容量,不应该看“最高能冲到多少QPS”,而应该看“在可接受的响应时间范围内,能稳定处理多少QPS”。

2.3 由等式推出三条提高吞吐量的基本路径

从“并发数 = QPS × RT”来看,方法其实已经被锁死了:如果系统的并发能力固定,要提高QPS,就必须降低RT;如果RT固定,要提高QPS,就必须增加并发能力。所以提高吞吐量只有三条路径:

  1. 降低响应时间:让每个请求更快结束,系统在同样时间内能处理更多请求;
  2. 增加并发能力:让系统同一时间能容纳更多在途请求,包括线程、连接、IO资源;
  3. 减少无效请求:让每个请求都更有价值,比如缓存、合并、拦截重复请求。

这三条路径听起来简单,但很多调优方案失败,是因为没有先判断当前瓶颈到底在哪条路径上。盲目加线程叫“增加并发能力”,但如果瓶颈在数据库连接池,加线程只会增加排队等待;盲目做缓存叫“减少重复计算”,但如果不是热点读问题,缓存收益会很有限。调优之前,先定位瓶颈比选技术方案更重要。

3. 压测时看到的指标和理论不一样:负载模型、拐点与容量判断

3.1 负载模型不同,指标完全不同

压测工具里常见的选项包括“并发用户数”“固定QPS”“阶梯加压”。需要区分“同时发请求的虚拟用户数”和“每秒请求数”之间的关系。假设压测工具模拟50个并发用户,每个用户连续不断发请求,接口平均RT是50ms,那么总QPS大约是 50 / 0.05 = 1000。想压到更高的QPS,应该调整虚拟用户数,而不是固定“每秒请求数”,否则很容易出现“瞬时打满、然后空等”的尖刺流量。

我给某个模拟项目X做压测时,一开始用固定QPS模式直接压到3000,结果服务RT飙升、错误率到10%;后来改成阶梯加压,从500 QPS起步,每10秒加500,结果系统到2500 QPS才开始出现拐点。同样一个“3000 QPS不合格”的结论,用不同压测方式得到的原因完全不同。所以压测报告必须写清负载模型、步长、持续时间,否则结论没法复现,也无法指导容量规划。

3.2 用RT曲线判断系统容量的三个阶段

压测过程中观察RT随并发升高的变化,通常可以看到三个区段:

  • 平直区:RT稳定,吞吐量线性上升;
  • 拐点区:RT开始抬升,吞吐量增速放缓;
  • 饱和区:RT快速爬升,吞吐量持平或下降,错误率上升。

判断容量上限,应该把“拐点区”作为容量边界,而不是等到饱和区或错误率爆发才叫停。很多团队习惯等错误率报警再降低压测压力,但其实那时候接口质量已经明显劣化,用户早就感知到了。我通常会给每个压测场景设定RT目标,比如P99超过500ms就标记为“容量预警”,哪怕成功率还是100%,也认为系统已经逼近容量边界。

3.3 虚拟用户数、线程池大小与并发数的换算

压测里的“虚拟用户数”并不等于服务器端的并发数。服务端的并发数取决于请求到达速度和处理速度。哪怕只压10个虚拟用户,如果接口RT是1秒,服务端同一时刻大约也就是10个在途请求;如果RT是10ms,10个虚拟用户轮询发请求,可以产生接近1000 QPS的到达量,但服务端真正的在途请求可能还是10个左右。

由此可以推导出配置原则:线程池大小、数据库连接池大小,应该根据“预期并发数 = 预期QPS × 预期RT”来配置。例如目标QPS是2000,当前RT是200ms,期望并发数就是 2000 × 0.2 = 400。那么服务线程池至少要能容纳400个工作线程,数据库连接池也要评估是否能同时满足400个并发连接需求;如果连接池上限只有50,那350个请求就会阻塞在连接池外,RT必然恶化。

4. 提高吞吐量的工程打法:从接入层到数据层逐级拆解

4.1 接入层:连接复用、超时控制和限流

接入层最常见的错误是把“连接数”当成“并发能力”。连接本身不消耗太多CPU,但连接上的请求会消耗。连接太多会把系统资源耗在文件描述符和内存缓冲区上,所以接入层的主要优化方向有三个:一是连接复用,通过keep-alive减少TCP握手的开销;二是设置合理的读超时和写超时,避免连接被慢客户端长期占用;三是在网关层做限流,防止突发流量直接打垮下游。

以常见的开源反向代理组件为例,keepalive超时、代理连接超时、代理读取超时、限流等参数组合起来,可以把“客户端慢”和“服务端忙”两类问题隔离开。接入层的目标不是让每个请求跑得更快,而是让“不该来的请求”和“拖时间的请求”不要进入核心链路。接入层一旦被慢客户端占满连接,真正重要的业务请求反而进不来,这是很多高并发事故的起点。

4.2 服务层:异步化、批量化和减少重复计算

服务层提高吞吐量的核心思路是压缩每个请求的处理时间,常用手段有三种:

第一是异步化:把不需要同步返回的操作丢到消息队列或异步线程池,让请求线程尽快释放。比如短信通知、审计日志、非关键数据同步。异步化需要监控消费端,我在项目里见过把“发送消息”改成异步后,接口QPS从500提升到1500,但消息队列积压持续上涨,最终消费端撑不住,反而拖垮了其他业务。

第二是批量化:把多个小请求合并成一个批量请求,比如批量查询、批量写入。单个请求的固定开销通过网络往返、线程调度等方式被摊销到多条数据上,吞吐量自然提升。

第三是减少重复计算:把热点数据、配置结果、权限结果缓存起来,避免每个请求都重复计算或重复读库。缓存不是银弹,但热点读场景下收益非常明显。

4.3 数据层:慢查询、连接池和缓存三板斧

数据库往往是整个链路里的最终瓶颈。十个请求里有八个要查库,数据库的吞吐上限直接决定整体吞吐。针对数据层的优化,我习惯固定三板斧的顺序:

先看慢查询。慢查询日志里如果有全表扫描、缺少合适索引的SQL,那么单次请求本身就太重,再加机器也扛不住。建立合适的索引,最好用覆盖索引减少回表。

再看连接池。连接池太小会导致请求排队,连接池太大又会让数据库资源耗尽。连接池大小的估算方式就是前面说的:预期并发数 = 预期QPS × 预期RT,然后结合数据库实例的CPU核数和IO能力确定上限。

最后看缓存命中率。如果命中率很低,说明大量重复请求还是打到了数据库。把热点读前置到缓存层,让数据库只处理写请求和缓存未命中的读,吞吐提升空间往往比调内核参数大得多。

4.4 水平扩展:加机器为什么有时候没用

提到提高吞吐量,很多人的第一反应是“加机器”。水平扩展确实可以线性提升吞吐,但前提有三个:请求能被均匀打散到多台机器、服务无状态、数据层能扛住成倍压力或已经做了分片扩展。如果数据库是一个单点,服务端从2台加到20台,数据库连接被打满,整体吞吐可能不升反降。

所以容量规划的顺序应该是:先让数据层具备扩展能力,再扩展无状态服务层。另外,加机器应该加在处理能力瓶颈上,而不是加在排队瓶颈上。如果瓶颈是某个第三方接口固定耗时300ms,加多少机器都只能干等,正确做法是异步化或想办法绕开这个慢调用。

现象可能瓶颈优先动作
RT随并发升高快速恶化线程切换/锁竞争缩小临界区、异步化、限流
CPU利用率不高但RT很高连接池/队列/IO等待调大连接池、减少同步等待
CPU打满、吞吐不再上升计算型瓶颈水平扩展、缓存计算结果
数据库慢查询增多数据层瓶颈索引、批量读写、缓存

5. 一次调优复盘:连接池排队造成的“资源空闲但吞吐上不去”

5.1 现象:CPU 40%但RT飙升

某个读多写少的业务系统,部署了2个服务实例,目标吞吐量是单接口QPS=1500,P95响应时间不超过300ms。初次压测结果:QPS跑到900左右,P95已经到800ms,错误率开始抬头。初步看,服务端CPU只有40%,看起来“资源还很空闲”,但响应时间很差。

这正是典型的“资源没打满,但吞吐上不去”状态。CPU还有60%的余量,说明问题大概率不在计算能力上,而在于某个共享资源在排队。最常见的隐藏瓶颈就是线程池、连接池、消息队列这类中间资源。

5.2 排查链路:从接入层到数据层逐层排除

当时我按三层去定位。先是接入层:检查连接数,发现网关联到服务的连接大约是300,keep-alive正常,没有慢连接占用,接入层排除。再是服务层:看线程池状态,工作线程还有空闲,但大量线程停在线程转态上,准确说是“等待获取数据库连接”。接着查数据库连接池状态,活跃连接一直在80左右,最大连接数配的是100,已经接近上限。

这时候基本可以锁定了:连接池被打满,请求在连接池外排队,队列越来越长,RT自然越来越高。CPU看起来空闲,是因为大部分时间都花在等待连接上,而不是计算上。这个案例最能说明一个道理:提高吞吐量不是先给系统“打鸡血”,而是先找到那个“看着不忙、其实在排队”的组件。

5.3 两轮调整与结果对比

第一轮调整:把数据库连接池最大连接数从100调到200。效果很直接,QPS从900提升到1300,P95降到450ms。第二轮调整:针对高频查询加了缓存,数据库读压力下降,连接占用从80降到30,QPS稳定到1600,P95稳定在250ms左右。最终服务端CPU仍然只有40%左右,但吞吐目标已经达成。

这个结果很能说明问题:第一轮调整是在解决“并发能力不足”的问题,让更多请求能同时进入数据库;第二轮调整是在解决“重复计算过多”的问题,让单位请求更快结束。两个方向都对,但顺序很关键——如果一开始就盲目加服务端线程池,反而会让更多线程去抢数据库连接,情况只会更糟。

5.4 一套可复用的调优顺序与检查清单

结合这次复盘,我整理了一套可以反复使用的调优顺序:

  1. 先定口径:吞吐量、QPS、并发数、RT全部统一到同一层统计,推荐以网关出口的成功请求口径为准;
  2. 压测用阶梯加压,观察RT拐点,不要只看最大QPS;
  3. 资源没打满但RT恶化,优先查连接池、线程池、队列等中间资源;
  4. 提高吞吐量优先选降低RT的方案,比如缓存、异步、批量,再考虑增加并发能力;
  5. 扩容前先确认数据层能撑住,否则只是把瓶颈从服务端挪到数据库。

我在实际项目中最大的体会是:这四个指标不是孤立的数字,而是一套互相约束的模型。先把并发数、QPS、响应时间的关系吃透,再配合压测去验证,很多看起来复杂的性能问题,无非是某个中间资源在排队。下次遇到系统吞吐量上不去,先别急着加机器,把连接池状态、线程池状态、RT分位数拉出来看一眼,往往已经能找到答案了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询