☰
Kali靶场Web应用压力测试与CC型压力防护实战
2026/11/4 3:26:50 网站建设 项目流程

1. 先弄清楚“CC”打的是什么:一次业务假死的复盘

凌晨两点,监控群里跳出一串告警:首页打不开、接口超时、5xx 比例飙到 30%,但服务器 CPU 只有 20% 出头,内存也没爆,带宽曲线平得像没事一样。值班的同事第一反应是“网络抖动”,重启了一遍服务,好了三分钟又不行。后来把 Nginx 的连接数和 upstream 响应时间拉出来看,才发现问题根本不在网络,而在业务处理链路:大量请求卡在数据库查询和模板渲染上,PHP-FPM 的进程池被占满,新请求排队排到超时。这就是典型的CC 型压力,也就是 Challenge Collapsar,消耗的不是带宽,而是应用层的处理能力。

我后来把这类问题统一归类为“WEB 应用压力测试没做够”的后遗症。真正的 CC 攻击模拟器并不神秘,它做的事就是持续、并发、带一定伪装地请求那些“最贵”的动态接口,让后端线程池、连接池、数据库连接、会话存储这些有限资源被慢慢吃干。你要防御它,第一步不是买设备,而是自己先能复现它。这篇内容讲的就是这件事:在Kali环境里,用常见的压测工具和 CC 模拟器,对自建靶场做一轮完整的压力测试,从靶场隔离、工具选型、参数计算、拐点判断,一直做到加固后的对照验证。

适合谁看?做后端和运维的同学,能拿到这里关于连接模型、限流配置、日志交叉验证的细节;做安全测试的初学者,能看清楚“压测”和“滥用”之间那条线到底画在哪;刚接手性能优化任务的人,也能直接抄走后面的阶梯加压脚本和结果记录表。前提只有一个:所有操作只在你拥有或已获得书面授权的系统上进行,靶场自己搭,别碰别人的站,这条线后面还会反复强调。

1.1 监控面板上最容易被误读的那条曲线

很多人判断“是不是被打”靠的是 CPU 曲线,这个习惯很危险。CC 型压力的资源消耗往往呈现“前端闲、后端忙”的分裂状态:Nginx 收请求很快,静态资源命中缓存,CPU 自然不高;但每一个动态请求都要走路由、鉴权、查库、拼模板,耗时 200 毫秒起步,并发一上来,工作进程就全被占住。

真正该盯的是四组数:活跃连接数、请求排队长度、上游响应时间、5xx 与超时的比例。当连接数持续爬升而 QPS 不涨,说明请求进来后出不去,队列在堆积;当 p95 响应时间从 200ms 跳到 2s 而 CPU 纹丝不动,基本可以确定瓶颈在数据库或外部依赖;当日志里出现大量同一路径、同一参数结构的请求,特征就更明显了。

我踩过的一个坑是:只看平均响应时间。平均值会被大量快速失败的请求拉低,看起来“还好”,实际上成功请求的耗时已经翻了十倍。后来我改成固定看 p95 和 p99,再配合错误率,判断准确率立刻上来了。这也是做压力测试时必须记录分位数的原因,平均值在这种场景下几乎等于自欺欺人。

1.2 动态请求为什么比静态文件“贵”几十倍

拿一个最普通的商品详情页举例。静态 HTML 文件由 Nginx 直接从磁盘或内存返回,一次处理可能只要几百微秒;而动态页要经过 URL 路由匹配、会话校验、参数过滤、缓存查询、数据库连接获取、SQL 执行、结果序列化、模板渲染,任何一环慢下来,整条链路就被拖住。这个过程消耗的是并发处理单元,也就是进程、线程或协程,数量是有限的。

这就解释了为什么 CC 模拟器偏爱搜索页、登录接口、带分页的列表页、导出接口这类目标:它们要么带复杂查询,要么需要写会话,要么触发大量计算。一个请求占住一个工作单元 500 毫秒,两百个并发就能把一百个进程池彻底占满。而静态资源即使被打,多数情况下只是带宽问题,加缓存、上 CDN 就能缓解,性质完全不同。

理解这一点,你的测试设计就会有针对性:不要拿首页静态图去压,要拿真实业务里最慢、最常被调用、最依赖下游的那几个接口去压。我通常会先从前端代码或网关日志里筛出调用量前 20 的接口,再按平均耗时排序,取交集作为压测目标清单。

1.3 压测与滥用的分界线:授权、范围、强度

技术上,压力测试和恶意请求用的是同一套方法,区别全在约束条件。我的做法是固定三条:授权书面化、范围白名单化、强度可控化。授权要写明目标域名或 IP、时间窗口、最大并发上限、联系人;范围用白名单限制,压测机只允许访问靶场地址,出站规则收死;强度用阶梯方式逐步加,每档观察后再决定是否继续,绝不一次性拉满。

还有一条容易被忽略:提前通知。哪怕是内部系统,也要让值班同事知道几点到几点在做压测,否则一个自动扩容策略被触发,或者告警风暴起来,大家都难受。我见过一次没打招呼的压测,把告警平台打爆,值班的人排查了四十分钟才发现是自己人干的。

提示:在云环境做压测,先看清楚服务条款里对压力测试的约定,有些需要提前报备。靶场一律用本地虚拟机或内网隔离环境,绝不要把测试流量指向公网上的任何第三方地址。

2. 靶场准备:把测试流量关进笼子

用完就跑的压测没有价值,能反复复现的靶场才有。我在 Kali 里做这类测试,习惯用“一机三用”的布局:Kali 做发起端,一台虚拟机跑 Nginx + 应用 + 数据库做靶机,另开一台轻量机器专门跑监控采集。三台机器放在同一个仅主机网络里,不接外网,压测机的出站规则只放行靶机地址。这样即使参数写错、并发拉爆,影响范围也出不了这个网段。

这套布局的好处是可观测。压测机上跑发起工具,靶机上跑采集脚本,两边时间同步,事后可以把“第几秒发了多少请求”和“第几秒响应时间飙升”对齐到同一条时间轴上。很多人的压测结果没法解释,就是因为发起端和靶机时钟不同步,日志对不上。

2.1 网络隔离与资源配额

隔离不只是不接外网。我还会给靶机做资源配额:CPU 限制在 2 核、内存 4G,模拟一台普通业务机的规格。为什么?因为如果你给它 16 核 32G,压出来的“承受能力”在真实环境里毫无参考价值。压测的意义是找到目标规格下的拐点,规格越贴近生产,结论越有用。

另外要给压测机留足余量。发起端自己也是要消耗 CPU 和端口的,如果压测机和靶机抢同一台物理机的资源,结果会被污染。我的经验是压测机至少留 2 核空闲,并且单独统计它自己的 CPU 使用率,一旦超过 70%,说明瓶颈可能已经在发起端了,这一轮数据就得作废重来。

还有个细节:关掉靶机上的自动更新和定时任务。有一次压测跑到一半响应时间突然抖了一下,查了半天发现是系统的定时任务在那几分钟跑了一次日志轮转,磁盘 IO 抢了资源。这种噪声在压测里必须提前排除。

2.2 靶机分层:从静态页到带库的业务链路

单一页面的靶场测不出真问题。我一般准备三层目标:第一层是纯静态页,用来验证压测工具本身是否正常、网络链路有没有问题;第二层是带模板渲染但不查库的动态页,用来单独观察应用层的处理能力;第三层是完整链路,包含会话校验、数据库查询、缓存读写,这才是最接近真实业务的场景。

三层分开压的好处是能定位瓶颈位置。同样 200 并发,静态页 p95 是 5ms,模板页是 30ms,完整链路是 400ms,那问题显然出在数据库或缓存那一段,后面的优化就有方向了。如果一上来就压完整链路,你只知道“慢”,不知道“哪慢”。

靶场应用我倾向用现成的开源靶场项目,功能齐全、有登录、有搜索、有数据库,省得自己写。数据库里灌个几万条数据,让查询有一点真实的工作量,但别灌太多,否则压测时磁盘 IO 会先成为瓶颈,掩盖应用层的问题。

2.3 先建基线再压:四类指标必须提前采集

压测前必须有一段“空载基线”。我的做法是空跑十分钟,采集四类数据:CPU 与内存的均值、活跃连接数的常态值、各接口的空载响应时间、错误率的零值确认。这组数据是后面判断“异常”的参照系,没有它,你看到 30% 的 CPU 也不知道是高是低。

采集手段不用复杂,vmstat、ss、top加上应用自身的访问日志就够。我习惯写一个十秒一次的采样脚本,把时间戳、连接数、CPU、内存、负载一起追加到 CSV 里,事后直接画图。日志格式也要提前确认,Nginx 的$request_time和$upstream_response_time必须开,这两个字段是后面交叉验证的核心,缺了就只能靠猜。

注意:采样脚本本身也会消耗资源,采样间隔不要低于 5 秒,字段也不要贪多。我见过有人每秒跑一次全量ps,结果采样进程自己成了负载来源。

3. 工具怎么挑:CC模拟器与常规压测器的能力边界

Kali 里能用的压测工具很多,ab、wrk、hey、siege、JMeter,还有一些专门做慢速请求和模拟浏览器行为的工具。很多人纠结“哪个最强”,其实这个问题问错了,应该问“我要测的是什么”。测吞吐上限用wrk,测固定速率下的稳定性用hey,测多 URL 混合场景用JMeter,测连接占用型行为用慢速请求工具,测单点极限用ab。工具没有高下,只有匹配不匹配。

至于所谓的 CC 攻击模拟器,剥开外壳看,核心能力就三件事:高并发发起、请求特征伪装、目标集中。你在授权靶场上要复现的,正是这三件事对服务端造成的资源消耗,而不是工具界面上那些花哨的按钮。理解了这一点,用wrk加一个随机参数脚本,效果和图形化模拟器没本质区别,还更容易控制强度、更容易记录数据。

3.1 并发模型的差别决定了你测的是什么

这是最容易被忽略的一层。ab是基于进程/线程的,并发数一高,压测机自己的上下文切换就成了瓶颈,测出来的数字往往偏低;wrk用事件循环加少量线程,单机就能压出很高的 RPS,但它的模型偏“理想化”,对真实浏览器的连接复用行为模拟得不够;JMeter是线程模型,功能全、能编排复杂场景,但吃内存,几百线程就得调堆参数。

工具并发模型适合场景主要短板
ab进程/线程单接口快速摸底高并发下自身开销大,不支持长连接复用细节
wrk事件循环 + 多线程测吞吐上限、找拐点场景编排能力弱,脚本需 Lua
heyGo 协程固定 QPS 下的稳定性复杂鉴权场景构造麻烦
siege多线程多 URL 混合、比例分配统计粒度较粗
JMeter线程组完整业务链路、参数化资源占用高,配置繁琐

我自己的组合是:先用ab做 50 并发的小摸底,确认链路通、参数对;再用wrk做阶梯加压找拐点;需要模拟登录态和混合比例时切到JMeter。这套组合跑下来,既快又能保证结论可靠。

3.2 请求构造:Cookie、UA、随机参数到底影响什么

服务端的限流和防护策略,很多时候是按来源特征做聚合的。如果你的压测请求全部一模一样,很容易被一层简单的规则挡住,测出来的“承受能力”是假的;反过来,如果每个请求都换 IP、换 UA、换 Cookie,那你测的就是防护设备的性能,而不是应用本身的性能。这两种目标要分清楚。

我的做法是分两轮。第一轮“裸压”,请求完全一致、不带任何伪装,目的是测应用本身的处理上限;第二轮“带特征压”,加入随机 URL 参数、轮换 UA、携带有效会话 Cookie,目的是验证防护策略在真实流量形态下是否有效。两轮结果对比,才能回答“加固到底提升了多少”。

构造随机参数有个小技巧:在 URL 后面加一个无意义的时间戳参数,比如?_t=加毫秒值。这样能绕过中间层的 URL 缓存,让请求真正落到应用上。如果你的目标是测缓存效果,那就反过来,故意不加随机参数,看命中率。测试目标决定构造方式,不要盲目照抄别人的脚本。

3.3 慢速请求:不拼数量的另一条路

有一类压力不靠并发数量,靠“占着不放”。慢速请求工具的思路是建立连接后,把请求头或请求体拆成很多小块,每隔一段时间发一点,让服务端一直等待,连接迟迟不释放。对于连接数上限不高的服务,几十个这样的连接就足以让新用户进不来。

在 Kali 里可以用slowhttptest做这类验证。它的关键参数是连接数、发送间隔、请求类型。我一般从很小的规模起步,比如 100 个连接、间隔 10 秒,观察服务端的活跃连接数和超时配置是否生效。这类测试对靶机的伤害不大,但对超时设置的检验非常有效。很多服务默认读超时是 60 秒甚至更长,一个慢连接就能占住一分钟,这个数字在真实环境里是要认真评估的。

# 慢速请求验证示例,仅用于本地靶场 slowhttptest -c 100 -H -g -o slow_report \ -i 10 -r 20 -t GET \ -u http://127.0.0.1:8080/search \ -x 24 -p 3

跑完之后重点看两件事:服务端的keepalive_timeout和client_body_timeout是否合理,以及连接数上限有没有被打到。参数调优的方向很明确,把不必要的长超时压短,把连接上限和排队策略配好。

3.4 并发数怎么算:别拍脑袋定参数

“我该开多少并发”是问得最多的问题。拍脑袋定一个 500 或者 1000,测出来的结果既不能解释也不能复现。正确的做法是从目标倒推,用 Little's Law:并发数 ≈ 目标 RPS × 平均响应时间(秒)。

举例:你希望系统稳定支撑 500 RPS,实测该接口平均响应时间是 200 毫秒,那么需要的并发是 500 × 0.2 = 100。如果响应时间在压力下涨到 800 毫秒,同样 500 RPS 就需要 400 并发才能维持,而此时线程池很可能已经撑不住了。这就是为什么要阶梯加压:响应时间会随压力变化,并发需求不是常数。

目标 RPS平均响应时间理论并发建议起始并发观察重点
100100ms1020错误率是否为零
300200ms60120p95 是否稳定
500200ms100200队列是否堆积
800400ms320400是否出现超时雪崩

表格里的“建议起始并发”通常是理论值的两倍,目的是留出余量观察拐点。实际执行时按 25%、50%、75%、100%、150% 这样分档往上走,每档稳定运行 60 到 120 秒,记录数据后再决定下一步。

4. 阶梯加压实战:找到系统真正的那条拐点

拐点是这套测试里最有价值的产出。它不是一个数字,而是一组条件:在多少并发、多少 RPS 下,系统的响应时间开始非线性上升,错误率开始出现,且持续不回落。找到它,容量规划就有了依据;找不到,你只能说“压过了没崩”,这句话在任何评审会上都站不住脚。

我一般的编排是五档:50、100、200、400、600 并发,每档 90 秒,档与档之间空跑 30 秒让系统回落。这样既能看到拐点,也能看到系统恢复能力。有些系统压的时候不崩,压力撤了之后连接迟迟不释放,五分钟才缓过来,这本身也是个问题。

#!/usr/bin/env bash # 阶梯加压脚本,仅用于授权靶场 TARGET="http://127.0.0.1:8080/search?keyword=test" for C in 50 100 200 400 600; do echo "=== concurrency: $C ===" wrk -t4 -c"$C" -d90s --latency "$TARGET" | tee "result_c${C}.txt" echo "cool down 30s" sleep 30 done

脚本很简单,关键在于每档都留存独立的结果文件,后面画曲线、写报告都靠它。

4.1 加压节奏与脚本编排

节奏控制比参数大小更重要。我见过有人直接从 0 拉到 1000 并发,跑了十秒就结束,结论是“系统扛住了”。这种测试毫无意义,因为很多问题需要时间累积才会暴露:连接池慢慢耗尽、内存逐步上涨、日志写满磁盘、缓存逐渐失效。持续时间太短,这些都不会出现。

我的经验是每档至少 90 秒,完整链路场景可以拉到 3 到 5 分钟。为什么是 90 秒?因为大多数连接池和线程池的排队效应在 60 秒内会显现,再加上 30 秒观察恢复,90 秒是一个比较经济的平衡点。如果是长连接场景,时间还要拉长,因为连接建立和回收的周期更长。

档间空跑也不能省。空跑期间观察三件事:活跃连接数是否回落到基线、响应时间是否恢复正常、错误率是否归零。如果压力撤了五分钟连接数还挂在高位,说明存在连接泄漏或者回收逻辑有问题,这比压测本身更值得关注。

4.2 拐点出现的三个信号

第一个信号是响应时间分位数跳变。不是平均值,是 p95 和 p99。正常情况下 p99 可能是 p50 的三到五倍,一旦这个比例扩大到二十倍以上,说明有请求开始排队了。

第二个信号是错误率的结构变化。零星超时是正常的,但如果错误从“超时”变成“连接被拒绝”,说明监听队列已经满了,问题从应用层下沉到了网络层,严重程度完全不同。

第三个信号是吞吐量平台期。并发从 400 加到 600,RPS 却停在 480 不动,响应时间还翻了一倍,这就是典型的饱和。此时再加并发只会让排队更长,不会让吞吐更高。

信号具体表现说明的问题
p99 相对 p50 比例超过 20 倍响应时间分布严重右偏请求开始排队
错误类型从超时转为连接拒绝accept 队列溢出连接层已达上限
并发翻倍但 RPS 不涨系统进入饱和区再加压无意义
压力撤后 5 分钟未回落连接或内存未释放存在泄漏风险

三个信号里,我认为第二个最危险,因为它意味着你连“排队”的机会都没有了,新用户直接被拒之门外。看到这个信号就该停止加压,先把连接层的问题解决掉。

4.3 服务端日志与压测结果的交叉验证

压测工具给的是客户端视角,服务端日志给的是服务视角,两边必须对得上,结论才可信。我习惯在压测结束后做三件事:统计 Nginx 访问日志里目标接口的请求总数,和压测工具报告的完成数对比;统计$upstream_response_time的分布,和客户端测到的响应时间对比;统计状态码分布,确认错误的具体类型。

差异超过 5% 就要查原因。常见的情况是中间层有缓存,请求根本没到应用;或者有重试机制,客户端一次请求在服务端变成了三次;再或者是日志缓冲区没刷盘,数据少记了一截。这些差异本身也是重要发现,说明你对链路的理解还有盲区。

# 统计目标接口的请求数与状态码分布 awk '$7 ~ /search/ {print $9}' access.log | sort | uniq -c | sort -rn # 提取 upstream 响应时间做分位统计 awk '$7 ~ /search/ {print $NF}' access.log | sort -n | \ awk '{a[NR]=$1} END {print "p50:",a[int(NR*0.5)],"p95:",a[int(NR*0.95)],"p99:",a[int(NR*0.99)]}'

这套统计跑下来,如果客户端报告 p95 是 1.2 秒,服务端日志算出来是 0.4 秒,那 0.8 秒的差距就出在网络传输或者中间层,优化方向立刻清晰了。

4.4 记录表:让结果能被别人复现

压测报告最怕写成一堆截图,别人看完不知道你怎么测的。我的记录表固定包含这些字段:测试时间、目标接口、靶机规格、压测机规格、并发数、持续时间、总请求数、RPS、p50/p95/p99、错误率、错误类型、服务端 CPU 峰值、连接数峰值、结论。

字段示例值备注
靶机规格2 核 4G模拟生产小规格
并发数200事件循环模型,4 线程
持续时间90s含 30s 观察期外
总请求数41200客户端报告
RPS458稳定段均值
p95820ms客户端视角
服务端 p95610ms日志交叉验证
错误率0.6%全部为超时
连接数峰值380服务端 ss 采样
结论拐点在 200 并发附近再高则错误率破 3%

有了这张表,换个人照着同样参数重跑,结果应该能复现到 10% 以内。复现不了,说明有隐藏变量没控制住,比如缓存状态、数据库索引、后台任务。

5. 防守端对照实验:加固之后必须再打一遍

压测只做一轮,价值减半。真正有用的是“加固前压一次,加固后再压一次,数据对比”。我见过太多团队做完优化就说“好多了”,问好多少,答不上来。有对照数据就不一样了,限流上了之后错误率从 12% 降到 0.3%,p95 从 3 秒降到 400 毫秒,这些数字才是能拿出去汇报的东西。

对照实验的前提是两轮条件一致:同样的靶机规格、同样的接口、同样的阶梯、同样的持续时间。中间只改一个变量,比如只加限流,或者只加缓存。多变量一起改,最后说不清是哪个起的作用。

5.1 限流限连接:Nginx两行配置的实际效果

应用层的第一个闸门是限流。Nginx 提供请求速率限制和并发连接限制,配置不复杂但效果立竿见影。

# 定义限流区域,按来源地址聚合 limit_req_zone $binary_remote_addr zone=req_per_ip:10m rate=20r/s; limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m; server { listen 8080; location / { limit_req zone=req_per_ip burst=40 nodelay; limit_conn conn_per_ip 30; proxy_pass http://backend; } }

rate=20r/s意味着单个来源平均每秒 20 个请求,burst=40允许短时突发 40 个,nodelay表示突发部分立即处理而不是排队延迟。limit_conn 30限制单来源最多 30 个并发连接。

这里有个我踩过的坑:nodelay用不好会造成“看起来限了其实没限”。如果不加nodelay,超出速率的请求会排队等待,队列长了照样占资源;加了nodelay,超出突发的请求直接被拒,返回 503。两种行为适用于不同场景,防护型场景我通常选nodelay,宁可快速拒绝也不要排队堆积。

限流阈值怎么定?不是拍脑袋。先看基线数据,正常用户单 IP 的峰值请求速率是多少,取它的三到五倍作为阈值,既能挡住异常流量,又不误伤正常用户。这个值必须用真实访问日志算,不能凭感觉。

5.2 缓存与页面静态化:把动态请求变便宜

限流是“堵”,缓存是“疏”。一个动态请求要 200 毫秒,命中缓存后可能只要 5 毫秒,同样的并发能撑住的量级完全不同。我的优先级是:能静态化的页面静态化,不能静态化的加页面缓存,页面缓存做不了的至少把数据库查询结果缓存住。

缓存最怕的是脏数据。压测时也要验证这一点,我一般会在压测中途手动改一条数据,看缓存是否按预期失效。如果改了数据页面十分钟不更新,这个缓存策略在业务上是不可接受的。TTL 设置要结合业务容忍度,商品列表可以缓存 30 秒,库存数量就不行。

页面静态化对防护的价值特别大,因为静态请求几乎不消耗应用资源。把首页、列表页这类高频访问且内容变化不快的页面生成静态文件,用 Nginx 直接返回,动态请求量能降一个数量级。这一招在压测对比里效果最明显,往往能让拐点直接往后推一大截。

5.3 人机校验与WAF的误伤面

再加一层就是行为识别和人机校验。思路是在可疑流量特征出现时,要求客户端完成一次校验,正常浏览器能过,脚本化的批量请求过不去。这层防护对 CC 型压力确实有效,但误伤风险也最高。

我见过一次配置失误,把同一个出口地址下的所有用户都判定为异常,因为公司网络出口是共享的,几百人共用一个来源地址,速率天然就高。结果正常办公的人全被挡在门外。所以这类策略上线前,必须用真实流量做灰度,观察误判率,并且准备好白名单和快速回滚方案。

误伤的处理原则是“宁可漏一点,不可错一片”。阈值设宽一点,配合告警,先观察再收紧。压测的作用在这里就体现出来了:你可以在靶场上把阈值调到刚好能挡住压力流量、又不影响正常请求的那个点,心里有数之后再上生产。

5.4 加固前后对比:用数据说话

把两轮数据放进同一张表,结论一目了然。

指标加固前加固后变化
200 并发下 RPS458470基本持平
200 并发下 p95820ms210ms下降 74%
400 并发下错误率12.4%0.3%下降 97%
600 并发下系统状态连接拒绝限流返回 503,核心接口正常从崩溃变为可控降级
压力撤后恢复时间5 分钟以上20 秒内明显改善

注意“加固后”不是“不报错”,而是“错误可控”。600 并发下依然有请求被拒,但拒绝发生在限流层,核心接口对正常用户仍然可用,这就是降级而不是雪崩。这个区别在汇报时一定要讲清楚,否则容易被理解成“没防住”。

6. 踩过的坑与必须守住的边界

这套流程我跑过很多轮,翻车次数不少,挑几个最有代表性的说说。

第一个坑是压测机先倒下。有一次用ab开 1000 并发,跑了半分钟结果全是超时,我以为靶机崩了,一查靶机好得很,是压测机的文件描述符上限到了,连接建不起来。后来第一件事永远是ulimit -n调到六万以上,并且把压测机自己的 CPU 使用率也纳入监控。

第二个坑是端口耗尽。短时间内大量短连接,客户端会积累大量 TIME_WAIT 状态的端口,可用端口不够,新连接就建不了。解决办法是开启tcp_tw_reuse、缩短 TIME_WAIT 时间,或者干脆用长连接模式压。长连接更接近真实浏览器行为,也更省端口,我现在默认开-k。

第三个坑是日志把磁盘写满。高并发下访问日志增长速度极快,一场压测下来几个 G 很正常。有一次靶机磁盘满了,应用写日志失败,报了一堆莫名其妙的错误,排查了很久。现在压测前一定检查磁盘余量,并且临时调低日志级别或者关闭不必要的调试日志。

第四个坑是DNS 解析成为瓶颈。压测目标如果用域名而不是 IP,每次请求都可能触发解析,尤其在某些工具的实现里解析是同步的。统一改成 IP 加 Host 头,问题消失。

第五个坑是结果不可复现。同样的参数,今天测出来 500 RPS,明天只有 300,查来查去是数据库索引没建、缓存没预热、后台任务刚好在跑。后来我固定了压测前置流程:清缓存、预热、确认无后台任务、记录数据库状态,四步做完再开压。

注意:以上所有操作的前提都是授权靶场。真实环境里,未经书面许可对任何系统发起压力请求,都可能造成业务中断并承担相应责任。这条线不要试探。

6.1 报告怎么写才有人看

技术报告最忌讳两件事:一是只有结论没有过程,二是只有截图没有数据。我的写法是先给一页摘要:测了什么、在什么条件下、发现了什么问题、建议怎么改,四个部分各三句话。后面再展开详细数据。

摘要里最重要的是一句话结论,比如“当前 2 核规格在 200 并发下 p95 达到 820 毫秒,主要瓶颈在数据库查询,加索引后预计可降至 300 毫秒以内”。这句话有现状、有定位、有预期,评审的人一眼就能抓住重点。

详细部分要有复现路径。参数、脚本、靶场规格、前置步骤,全部写清楚。我甚至会附上原始结果文件,别人想自己算一遍分位数随时可以。这比任何华丽的图表都更有说服力。

6.2 我个人在实际操作中的体会

做了这么多轮压测,最大的感受是:压力测试的价值不在“压”,在“测”。把并发拉满谁都会,真正难的是设计出能暴露问题的场景,以及把结果解释清楚。我见过太多人压完之后只记得一个“最高 RPS”的数字,问他瓶颈在哪、怎么优化,答不上来,那这场测试基本白做。

第二个体会是,先修监控再做压测。没有分位数、没有连接数、没有上游响应时间,压出来的数据没法解读。我现在开工前会花半小时确认日志字段和采样脚本,这半小时能省掉后面几小时的扯皮。

第三个体会是,小步慢走比一步到位安全。阶梯加压看着慢,但每一档都能停下来观察、随时可以终止,比一次性拉满然后手忙脚乱强太多。这套方法用在容量规划、版本对比、防护验证上,都成立。后面如果还要往下做,我会把压测接进持续集成的流水线,每次发版自动跑一轮基准场景,把性能回归在代码合并前就拦住,这比上线后再救火省事得多。

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

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

立即咨询