老张的“AI 小灶”餐厅准备开新店,他最担心的不是菜谱,而是晚高峰后厨能不能顶住。于是他决定在开业前搞一场“试营业演习”:请来几波模拟客人,按真实点菜节奏涌入餐厅,观察后厨平均多久出一桌菜、等位区堆了多少人、哪个灶台最先撂挑子。演习结论决定了他敢放多少张桌子、要不要多招一名切配师傅。这套“先演习、再开业”的玩法,就是软件世界的性能压测——在上线前用工具模拟真实流量对系统施压,测出它的极限、瓶颈和稳定性。本文将沿着这场演习的完整流程,讲清压测工具怎么选、场景怎么设计、压力怎么加、结果怎么解读,让你成为能帮团队“验菜”的那位压测主厨。

岗位关联

学会性能压测,你就能在系统上线前预告风险、在流量洪峰前算清容量,成为线上稳定性的“第一道防火墙”,这是测试工程与 SRE 岗位最硬核的看家本领。

目录
  1. 可视化演示
  2. 压测基础概念
  3. 压测工具选型
  4. 压测场景设计
  5. 渐进加压策略
  6. 压测执行实施
  7. 结果分析与瓶颈定位
  8. 压测实战应用
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示JMeter/Locust/k6工具性能对比、阶梯式加压策略与性能拐点瓶颈定位,通过模式切换理解高并发压测核心流程与结果分析方法。

本节配有交互动效(进入视口后自动加载,约 3KB)。

工具对比:JMeter/Locust/k6性能差异 JMeter基于JVM,GUI丰富但单机并发约2k-5k Locust基于gevent协程,单机可达1w-2w并发 k6(Go) > Locust(Python) > JMeter(Java) in throughput k6基于Go引擎性能最高,脚本即代码可维护性最佳

压测基础概念

老张在试营业演习前,先想明白一个问题:他要测的到底是什么?答案不是“厨房厉不厉害”,而是“在客人最多的晚高峰,后厨能不能在客人可接受的等待时间内,把每桌菜都端出去”。软件里的性能压测也一样——它不是玄学,而是给系统来一场事先排练的“晚高峰”。

压测(Pressure Test)通过工具模拟大量用户请求,对系统施加接近甚至超过预期的负载,观察系统在压力下的表现。它回答三个问题:系统能承受多大流量(极限)、在可承受范围内响应快不快(性能)、长时间高压会不会垮(稳定)。由此衍生出三类测试:负载测试验证预期负载下的表现,压力测试寻找崩溃点,稳定性测试考察长时间运行。

压测的三大核心指标构成一切分析的基础。并发用户数是同时向系统发请求的模拟用户数;吞吐量(QPS/TPS)是单位时间完成的请求数,好比后厨每小时端出的菜品数;响应时间是每个请求从发出到返回的耗时,好比客人从点餐到上桌的等待。三者之间有一个著名的关系式——Little 定律:

演习结束时,老张把这套“锅有多大、端得有多快、等得有多久”的关系记进账本:先定客人能接受的最长等菜时间,再倒推需要多大锅和几个灶台。压测的第一课,就是学会用这套三角关系读懂系统的“后厨账本”。

N=λ×R\displaystyle N = \lambda \times R
并发数 = 吞吐量 × 平均响应时间。三个指标互相牵制:吞吐高了响应必然变慢,想同时提升二者就要增加系统资源。
  1. 并发数 N系统中同时处于处理状态的请求总数,对应餐厅里同时举着筷子等菜的客人桌数。
    N\displaystyle N
  2. 吞吐量 λ单位时间内完成处理的请求数量,对应后厨平均每秒钟端出的菜盘数。
    λ\displaystyle \lambda
  3. 平均响应时间 R单个请求从进来到完成的平均耗时,对应每桌客人从下单到上齐菜的平均等待。
    R\displaystyle R
  4. 乘积守恒三者相乘表示“锅里有多少、端得有多快、等得有多久”必须守恒——任何一项失衡,就说明某处堵住了。
    N=λ×R\displaystyle N = \lambda \times R

压测工具选型

定下演习目标后,老张开始挑“模拟客人”。他有三套方案:请一队职业试吃员按固定节奏进店,请一群灵活兼职的学生随机进店,或者用一套自动叫号系统在门口批量放号。三套方案各有拥趸——这就是压测工具选型。

JMeter 是资格最老的“职业试吃团”。基于 Java 线程池模型,一个线程即一个虚拟用户,支持 GUI 录制脚本、插件生态丰富(数据库、消息队列、Web 服务),适合已有 Java 技术栈、需要图形化编排脚本的企业团队。缺点是线程模型在单机上撑不了太高并发,增加虚拟用户意味着增加线程资源,施压机自己容易先“累倒”。

Locust 是“灵活兼职团”:基于 Python 协程(gevent)实现,单进程就能模拟成千上万用户;脚本就是普通 Python 代码,适合编排登录、下单、支付等复杂业务链路。k6 则是“自动叫号机”:Go 编写,脚本用 JavaScript 描述,单机并发能力高、命令行友好,天生为 CI/CD 集成设计,适合开发自测和流水线回归。

选型看三个维度:语言生态(团队熟悉 Java 选 JMeter、熟悉 Python 选 Locust、要轻量集成 CI 选 k6)、单机并发能力(协程模型远强于线程模型)、可维护性(脚本即代码更容易做版本管理与评审)。选型前还要算清压测机的规模——要模拟目标并发需要多少台施压机:

老张最后没请“职业试吃团”,因为他的主厨团队是 Python 出身,兼职团写脚本最顺手。选工具没有绝对的好坏,只有跟团队能力、业务场景配不配——就像后厨招人,不选最贵的,只选能一起颠勺的。

M=⌈NtCm×η⌉\displaystyle M = \left\lceil \frac{N_t}{C_m \times \eta} \right\rceil
所需压测机台数 = 目标并发数 ÷(单机可模拟并发数 × 安全系数)后向上取整。先算清“需要多少并发、几台机器能压出来”,再决定工具与部署形态。
  1. 目标并发 N_t压测计划要模拟的并发用户总数,来自业务峰值估算。
    Nt\displaystyle N_t
  2. 单机并发上限 C_m一台施压机在保证自身稳定时能模拟的并发数,JMeter 受线程与内存限制通常为几百到几千,Locust/k6 借助协程可达数万。
    Cm\displaystyle C_m
  3. 安全系数 η预留 20%–40% 余量,防止施压机 CPU 或内存被打满而自身成为瓶颈,通常取 0.6~0.8。
    η\displaystyle \eta
  4. 向上取整 M实际需要的压测机台数,M 大于 1 时就要考虑分布式压测架构。
    M=⌈NtCm×η⌉\displaystyle M = \left\lceil \frac{N_t}{C_m \times \eta} \right\rceil

压测场景设计

演习不能只测“客人全点招牌菜”这一种情况。老张翻出上周的菜单流水单,发现招牌菜占六成、家常菜占三成、酒水占一成,于是按这个比例安排模拟客人点菜。压测场景设计同理:先提取业务模型,再设计场景,最后准备数据。

业务模型提取是从线上日志统计各接口的调用占比、读写比例、核心链路依赖,就像从流水单算菜单比例;场景类型划分则是组合出若干压测场景:容量测试场景(模拟预期峰值负载)、峰值冲击场景(瞬间涌入高于预期的流量)、混合场景(不同接口按真实比例并发)。测试数据准备要解决“菜不能老是一盘”的问题——每个虚拟用户需要不同的账号、商品、关键词,避免命中缓存造成假象。

场景设计首先要回答“压多少合适”。从业务指标估算目标每秒请求数,常用的公式是:

老张把“六三一”的菜单比例贴在传菜口,模拟客人照单点菜,结果发现是酒水柜成为瓶颈——因为冰杯来不及供应。压测场景设计的意义就在于此:不按真实比例施压,就永远发现不了“酒水柜”这种隐藏瓶颈。

Q=D×pT\displaystyle Q = \frac{D \times p}{T}
目标每秒请求数 = 业务用户数 × 人均请求次数 ÷ 统计时间。压测负载不是拍脑袋定的,而是从业务数据里算出来的。
  1. 业务用户数 D日活跃用户或目标在线用户数,对应演习当天可能进店的客人总数。
    D\displaystyle D
  2. 人均请求次数 p每个用户完成一次业务操作平均产生的请求数,对应每位客人平均点几道菜。
    p\displaystyle p
  3. 统计时间 T通常取 86400 秒(一天),也可以只取业务高峰窗口如 3600 秒,秒数越小算出的 QPS 越贴近峰值。
    T\displaystyle T
  4. 目标每秒请求数 Q作为压测场景的基准负载,再乘上峰值系数得到最终加压目标。
    Q=D×pT\displaystyle Q = \frac{D \times p}{T}

渐进加压策略

老张不会一开门就放 500 桌客人进来——万一把后厨冲垮,连原因都来不及看。他选择先放 20 桌,观察 5 分钟;一切稳定,再加 20 桌;直到发现某档客人等菜时间明显变长,就停下来记录。这就是渐进式加压。

阶梯式加压把负载分成若干档,每档保持一段时间,让系统指标充分暴露后再升下一档。它和瞬间全量压入的区别在于:瞬间全量只告诉你“挂了”,渐进加压却能告诉你“在哪一步开始扛不住”。峰值冲刺测试在阶梯测试完成之后进行,直接以预估峰值并发冲击系统并保持一段时间,验证系统在峰值下的稳定性。容量探底则继续往上加,直到错误率失控、响应时间爆表,彻底摸清系统真实上限。

阶梯加压每一档的并发数按比例均匀递增:

演习那天,老张在 80 桌时第一次看到出餐速度拐头,他立刻在这一档记录下所有监控数据。后来他常说:压测不是比谁跑得快,而是比谁能在“垮掉之前”看清每一步——这就是渐进加压的价值。

Li=Lmax⁡×iK,i=1,2,…,K\displaystyle L_i = L_{\max} \times \frac{i}{K}, \quad i = 1, 2, \ldots, K
第 i 档并发 = 目标最大并发 ×(当前档位 ÷ 总档数)。档位越多,对拐点的定位越精细。
  1. 目标最大并发 L_max压测最终要冲击的并发上限,来自场景设计的峰值估算。
    Lmax⁡\displaystyle L_{\max}
  2. 总档数 K把加压过程切成 K 档,每档停留一段时间观察指标,通常取 5~10 档。
    K\displaystyle K
  3. 当前档位 i从 1 到 K 逐级上升,系统每扛过一档才进入下一档,保证每档指标都被完整记录。
    i\displaystyle i
  4. 第 i 档并发 L_i每档并发 = 最大并发 × 档位比例,形成一条平滑的阶梯曲线。
    Li=Lmax⁡×iK\displaystyle L_i = L_{\max} \times \frac{i}{K}

压测执行实施

演习绝不能在后厨正忙着接外卖单的时候进行,否则根本分不清是外卖订单还是演习客人拖垮了灶台。老张选择周一闭店日包场,还单独开辟一条测试通道。压测执行的第一要务,就是环境隔离。

环境隔离分两层:一是基础设施隔离,尽量使用专用的压测环境,数据库用影子库或脱敏数据,避免污染线上数据;二是流量隔离,若必须生产压测,要对请求打标、限定用户范围、配置熔断开关,防止事故扩散。接下来是分布式压测:当单台施压机无法模拟足够并发时,采用 Master-Worker 架构,一台主控机分发任务、多台施压机同时施压、主控汇总结果。最后是监控数据采集:除了压测工具自身的指标,还要同步采集系统指标(CPU、内存、IO、网络)、应用指标(中间件队列深度、连接池、GC)、业务指标(错误率、超时数),三者对齐到同一时间轴才能定位瓶颈。

监控采样的数据量决定了分析的精度:

演习当天,老张在监控室同时盯着三块屏:一块看出餐速度,一块看灶台火候,一块看传菜口排队。任何一块出现异常,他都能立刻说出“是哪一秒、哪个环节”出了问题——这就是同步采集监控数据的力量。

P=T×f\displaystyle P = T \times f
监控数据总点数 = 压测持续时间 × 采样频率。采样太稀会漏掉尖峰,采样太密会挤爆存储。
  1. 压测时长 T单档压测的持续时间,单位秒,通常每档保持 3~10 分钟让系统进入稳态。
    T\displaystyle T
  2. 采样频率 f每秒从系统采集多少组指标数据,常用 1~10 Hz,对应监控探针的抓取间隔。
    f\displaystyle f
  3. 总数据点数 P压测结束后可供分析的数据量,P 足够大才能拟合趋势、定位精确到秒的尖峰。
    P=T×f\displaystyle P = T \times f

结果分析与瓶颈定位

演习结束,老张对着监控回放一遍:晚高峰第 40 分钟出餐突然变慢,切配台的排队最长。他把“出餐慢”拆开看——不是炒锅不够,是切配师傅的手速跟不上。结果分析的价值,就是把“系统变慢”拆成“到底慢在哪个环节”。

结果分析分四步。指标趋势解读:把吞吐量、响应时间、错误率画在同一时间轴上观察走势,重点看响应时间是否随并发增长出现“拐头向上”。拐点识别:吞吐量不再增长甚至下降的并发点,就是系统的容量极限。瓶颈根因定位:先看资源层(CPU 用户态/内核态、内存换页、磁盘 IO),再看中间件层(数据库慢查询、Redis 命中率、消息积压),最后看应用层(线程池、连接池、GC);每一层都用火焰图或链路追踪确认。优化回归验证:修复瓶颈后重新压测,对比优化前后的拐点位置。

判断系统是否逼近极限,可以用排队论中的利用率模型:

老张最终定位到问题:不是灶台少,而是切配台的刀只有一个。他加了一把刀、优化了配菜流程,第二天重跑演习,同样的 80 桌客人,出餐时间降了四成。压测的闭环不是“测出问题”,而是“测出问题—定位根因—优化—再验证”。

ρ=λμ\displaystyle \rho = \frac{\lambda}{\mu}
系统利用率 = 请求到达率 ÷ 服务率。ρ 超过 0.85 时,请求开始在队列中堆积,响应时间急剧劣化。
  1. 到达率 λ单位时间内到达系统的请求数,相当于客人涌向后厨点菜的速率。
    λ\displaystyle \lambda
  2. 服务率 μ单位时间内系统最多能处理的请求数,相当于后厨满负荷出餐的速度上限。
    μ\displaystyle \mu
  3. 利用率 ρ到达率与服务率的比值,ρ < 0.7 为健康区,0.7~0.85 为关注区,> 0.85 为危险区——队列开始堆积,等待时间失控。
    ρ=λμ\displaystyle \rho = \frac{\lambda}{\mu}

压测实战应用

演习报告出来后,老张做了三个决定:把餐厅接客上限从 100 桌调到 80 桌;根据晚高峰预测提前安排兼职排班;每周三闭店做一次全流程疏通演练。这三个决定,正好对应压测在工程实践中的三大应用。

上线前容量验证:新版本上线前跑一轮压测,用数据回答“这个版本能不能扛住预期流量”,支撑发布决策——就像新菜上线前先在后厨试做三天。容量规划扩缩容:用压测实测的单实例处理能力反推需要多少实例,杜绝“拍脑袋扩容”——就像根据 80 桌的极限决定备多少食材、排多少班次。稳定性压测:以 70%~80% 的负载长期运行(数小时到数天),验证内存泄漏、连接泄漏、日志积压等问题——就像连续一周满座营业,看后厨会不会越做越乱。

容量规划的核心是“用实测数据说话”。单实例处理能力来自压测,而不是厂商宣传或经验估算:

老张的餐厅开业三个月,晚高峰再也没有出现“等菜一小时”的差评。他把演习的数据贴在墙上,逢人就说:所有自信都来自开业前那场试营业。系统的稳定性也一样——压测不是给老板看的 PPT,而是给用户吃下的定心丸。

M=⌈QPSpeak×(1+s)qpsper×u⌉\displaystyle M = \left\lceil \frac{QPS_{peak} \times (1 + s)}{qps_{per} \times u} \right\rceil
所需实例数 = 峰值请求量 ×(1 + 冗余比例)÷(单实例处理能力 × 目标水位)。每一项都必须有数据依据。
  1. 峰值请求量 QPS_peak业务侧预测的最高每秒请求数,来自运营活动和用户增长分析。
    QPSpeak\displaystyle QPS_{peak}
  2. 冗余比例 s为超预期流量留出的缓冲,通常取 0.1~0.3,对应后厨多备 20% 食材。
    s\displaystyle s
  3. 单实例能力 qps_per压测实测得到的单台服务处理能力,是整个公式最可靠的数据源。
    qpsper\displaystyle qps_{per}
  4. 目标水位 u期望资源利用率上限,如 0.6 表示 CPU 最多用到 60%,保留下探空间。
    u\displaystyle u
  5. 向上取整 M最终扩容的实例数,压测数据让扩缩容从“感觉”变成“算术”。
    M=⌈QPSpeak×(1+s)qpsper×u⌉\displaystyle M = \left\lceil \frac{QPS_{peak} \times (1 + s)}{qps_{per} \times u} \right\rceil

AI 应用场景

LLM 推理服务上线前压测

阶段:模型部署上线 / 系统性能验证

解决的问题:大模型推理服务成本昂贵,单实例并发能力取决于显存、动态批处理(batching)策略和上下文长度,不压测就无法确定该部署几个 GPU 实例,也无从承诺给用户的响应时间 SLA。

具体案例:某 AI 客服平台上线前用 k6 对对话接口渐进加压,发现单实例并发超过 20 时 TP99 从 1.8 秒飙到 6 秒以上,进一步定位为显存不足导致 batch 强制缩小。根据压测数据,团队把 GPU 实例从 1 台扩到 3 台并开启动态 batching,重测后 TP99 稳定在 2 秒内。

大促流量容量规划

阶段:容量规划 / 成本优化

解决的问题:大促或新功能上线前,运维靠经验扩容经常造成“扩多了浪费、扩少了宕机”。压测提供实测的单实例 QPS 上限,让扩容有据可依。

具体案例:某电商推荐服务预估大促峰值 50 万 QPS,压测测出单实例上限 8000 QPS,按目标水位 0.6、冗余 20% 计算需要 125 个实例,比往年拍脑袋扩的 160 台节省了 35 台的成本,峰值当天全程无降级。

微服务链路瓶颈定位

阶段:性能调优 / 根因分析

解决的问题:分布式系统变慢时,表象在 A 服务,根因可能在 B 服务或数据库。压测结合全链路监控,能准确指出“瓶颈在哪一层”。

具体案例:某 AI 中台对外提供特征服务,压测到 300 并发时响应时间陡增,但 CPU 利用率只有 40%。通过链路追踪发现数据库连接池被打满,请求阻塞在获取连接上。优化连接池参数后,同样并发下 TP99 下降 70%。

Python 演示

python69 行
import timeimport threadingimport random  class MockBackend:    """带并发上限的模拟后端,类比只有 5 个灶台的后厨"""     def __init__(self, max_workers, base_latency):        self.max_workers = max_workers        self.base_latency = base_latency        self.active = 0        self.lock = threading.Lock()     def handle(self):        with self.lock:            if self.active >= self.max_workers:                return False            self.active += 1        time.sleep(self.base_latency + random.random() * 0.02)        with self.lock:            self.active -= 1        return True  def percentile(data, p):    if not data:        return 0.0    data = sorted(data)    idx = min(len(data) - 1, int(len(data) * p))    return data[idx]  def run_scenario(concurrency, duration, backend):    latencies = []    failures = 0    total = 0    stop_event = threading.Event()     def worker():        nonlocal failures, total        while not stop_event.is_set():            total += 1            t0 = time.time_ns()            ok = backend.handle()            dt = (time.time_ns() - t0) / 1e9            if ok:                latencies.append(dt)            else:                failures += 1            time.sleep(0.01)     threads = [threading.Thread(target=worker) for _ in range(concurrency)]    for t in threads:        t.start()    time.sleep(duration)    stop_event.set()    for t in threads:        t.join()     success = len(latencies)    print(f"并发 {concurrency:>2} | 请求 {total:>4} | QPS {success / duration:5.0f} | "          f"错误率 {failures / total:6.2%} | TP99 {percentile(latencies, 0.99) * 1000:5.0f}ms")  if __name__ == "__main__":    backend = MockBackend(max_workers=5, base_latency=0.03)    for conc in [1, 2, 5, 10, 20]:        run_scenario(conc, 2, backend)
目的:用线程模拟虚拟用户,对一个带 5 并发上限的“模拟后端”做阶梯式加压,输出每一档的 QPS、错误率和 TP99,直观演示渐进加压与拐点定位。
  1. class MockBackend模拟一个最多同时处理 5 个请求的后端,类比只有 5 个灶台的后厨。
  2. if self.active >= self.max_workers: return False并发超限时拒绝请求(模拟连接池耗尽、请求失败)。
  3. time.sleep(self.base_latency + random.random() * 0.02)模拟处理耗时,加入少量随机抖动更贴近真实服务。
  4. while not stop_event.is_set():每个虚拟用户持续发请求,直到压测结束信号触发,对应压测的持续施压。
  5. percentile(latencies, 0.99)计算 TP99,筛选出最慢的 1% 请求,比平均值更能反映长尾体验。
  6. for conc in [1, 2, 5, 10, 20]:阶梯式加压:并发从 1 升到 20,观察错误率与 TP99 在哪一档开始失控。

常见误区

误区压测就是要往死里压,把系统打到 500 错误、机器 CPU 100% 才算有成果,最好连压测机也一起打满。

正解压测的目标是量化系统在真实业务场景下的能力和边界,而不是一场“摧毁比赛”。把系统打崩只能证明“它崩了”,却无法回答“它还能安全扛多少”。科学的做法是渐进加压,找到业务可接受的拐点并记录下来,让开发团队有数据可修复、让老板有数据可决策。

为何常见:初学者容易把压测等同于压力测试,忽略了负载测试和稳定性测试同样是压测家族成员,追求“极限数值”比追求“可用结论”更有成就感。

误区压测报告里平均响应时间 200ms,说明系统很快,可以放心上线。

正解平均响应时间会被少数快请求拉低,掩盖大量慢请求的真实体验。正确做法是看 TP90、TP99、TP999:TP99 表示 99% 的请求在这个时间内完成,剩下的 1% 才是用户真正会吐槽的“卡顿”。一次晚高峰,也许 99% 的客人 5 分钟吃上饭,但那 1% 等了 40 分钟的客人,会在点评软件上给一星。

为何常见:平均数是小学数学,人人都懂;百分位数需要排序和统计思维,且报表工具默认展示平均值,导致团队习惯性看平均数。

误区本地开发机直接跑 JMeter 压测本机服务,图省事,反正压的是“同一个后厨”。

正解施压机和被测系统共用 CPU、内存、网络,压测机自身的资源竞争会污染所有指标——你测到的可能不是系统的瓶颈,而是压测机抢资源导致的“假瓶颈”。正确做法是环境隔离:施压机、被测服务、监控系统分别部署,网络走独立链路。

为何常见:本地压测启动最快、无需申请环境,出了问题还能一边断点一边压,但恰恰是这种“方便”让数据彻底失真。

误区压测报告写了“数据库慢查询导致瓶颈”,任务就算完成,优化是开发的事。

正解压测的闭环是“发现—定位—优化—回归”。优化后必须用同一套场景和并发重新压测,对比拐点是否后移、TP99 是否下降、吞吐是否提升。没有回归数据的报告只是一张“体检单”,不验证药效的医生不是好医生。

为何常见:回归压测要重新搭建环境和执行流程,耗时且“结果已知”,容易被团队当作重复劳动跳过,导致优化无效甚至引入新问题而不自知。

面试题

Q1. Little 定律 N = λ × R 中,若吞吐量翻倍而平均响应时间不变,并发数如何变化?

单选题 · easy

  • A.并发数减半
  • B.并发数不变
  • C.并发数翻倍← 正确答案
  • D.无法直接确定

答案:C。Little 定律是乘法关系,吞吐量 λ 翻倍、响应时间 R 不变,则乘积 N 翻倍。就好比后厨每秒钟端出的菜翻倍、每桌等菜时间不变,那同时等着吃饭的桌子数必然翻倍。

Q2. 下列哪个指标最能反映绝大多数用户的真实等待体验?

单选题 · easy

  • A.平均响应时间
  • B.TP99 分位数值← 正确答案
  • C.最大响应时间
  • D.系统吞吐速率

答案:B。TP99 表示 99% 的请求在某个时间内完成,剔除了极端噪声又能暴露长尾;平均响应时间会被快请求掩盖慢请求的问题,最大响应时间又容易被单次抖动带偏。

Q3. JMeter 的虚拟用户是基于什么模型实现的?

单选题 · easy

  • A.基于线程实现← 正确答案
  • B.基于协程实现
  • C.基于进程实现
  • D.基于事件循环

答案:A。JMeter 每个虚拟用户对应一个 Java 线程,线程占内存且切换开销大,所以单机并发上不去;这也是它和 Locust、k6 在并发能力上拉开差距的根本原因。

Q4. Locust 能单机模拟大量虚拟用户的核心原因是什么?

单选题 · mid

  • A.架构基于 Python 协程← 正确答案
  • B.架构基于 Java 线程
  • C.架构基于 C 多进程
  • D.架构依赖硬件中断

答案:A。Locust 用 gevent 协程模拟用户,协程是用户态轻量调度,内存开销远小于线程,所以单进程能模拟上万并发。就好比兼职学生可以用“一队人分时复用”的方式模拟大批客人。

Q5. 阶梯式加压策略的主要目的是什么?

单选题 · mid

  • A.提升系统吞吐量
  • B.延长压测时长
  • C.寻找系统性能拐点← 正确答案
  • D.减少压测机数量

答案:C。阶梯加压把负载分成多档逐步抬升,让系统在每一档都进入稳态并记录指标,从而精确定位“从哪一档开始扛不住”,即性能拐点。瞬间全量压入只能知道系统挂了,不知道它是在哪一步垮的。

Q6. 压测中,若吞吐量持续增长但响应时间突然陡增,最可能说明什么?

单选题 · mid

  • A.网络出现抖动
  • B.压测机自身故障
  • C.系统处理变快了
  • D.达到容量拐点了← 正确答案

答案:D。吞吐量增长到一定程度后,资源耗尽导致请求排队,响应时间出现非线性陡增,这就是容量拐点。此时继续加压只会让错误率上升,吞吐量甚至会回落。

Q7. 某系统 CPU 利用率仅 60% 时 TP99 已严重劣化,下一步最合适的排查动作是什么?

单选题 · mid

  • A.继续加压观察变化
  • B.排查锁竞争等隐瓶颈← 正确答案
  • C.直接对 CPU 扩容
  • D.结束压测改日再说

答案:B。CPU 不高但响应劣化,说明瓶颈不在 CPU 而在其他环节:数据库连接池耗尽、锁竞争、磁盘 IO 限流等。直接扩容 CPU 是典型的“头痛医头”,必须先定位真正的根因。

Q8. 容量规划公式 M = ⌈QPS_peak × (1 + s) ÷ (qps_per × u)⌉ 中,u 的含义是什么?

单选题 · hard

  • A.峰值流量系数
  • B.容量冗余系数
  • C.目标资源水位← 正确答案
  • D.期望并发人数

答案:C。u 是目标资源利用率上限,比如 0.6 表示期望 CPU 最多用到 60%,为流量毛刺和故障转移留出空间。s 才是冗余比例,二者不能混淆。

Q9. 压测场景设计阶段需要完成哪些工作?

多选题 · mid

  • A.线上业务模型提取← 正确答案
  • B.参数化的测试数据← 正确答案
  • C.场景类型组合设计← 正确答案
  • D.服务器采购合同

答案:ABC。场景设计三件套是业务模型(接口占比)、测试数据(参数化避免缓存假象)、场景组合(容量/峰值/混合场景)。采购合同属于容量规划落地阶段,不是场景设计的内容。

Q10. 以下哪些信号可以判断系统已接近性能极限?

多选题 · hard

  • A.错误率开始明显上升← 正确答案
  • B.响应时间出现拐点← 正确答案
  • C.吞吐量不再继续增长← 正确答案
  • D.施压机负载仍然很低

答案:ABC。错误率上升、响应时间拐头、吞吐量停滞是系统逼近极限的三大标志,对应利用率 ρ 逼近 1 时的排队现象。施压机负载低说明压力还没到位,恰恰证明系统还没到极限。