ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零搭建Linux网络压力测试环境:Shell脚本实现自动化发包与性能分析

从零搭建Linux网络压力测试环境:Shell脚本实现自动化发包与性能分析 简介本资源是一套面向网络安全研究人员与防御工程师的DDoS攻击原理与工具实践教学包聚焦于发包机系统搭建、流量生成机制及常见反射放大攻击如DNS/SSDP/NTP/UDP Flood等的技术实现。资源共152个文件涵盖38个C语言攻击模块含SYN、ACK、RST、FIN、Slowloris等变种、31个网络数据包样本.pkt、24个PHP服务端利用脚本、10个说明文档.txt/.md以及关键视频教程.wmv和源码级攻击脚本.py/.sh/.c。压缩包大小为50.83MB结构清晰按扫描探测、目标过滤、协议构造、流量放大、日志分析等逻辑分层组织。已有3663人学习下载可帮助读者深入理解DDoS攻击链各环节掌握真实环境下的工具编译、参数调优与流量特征模拟方法为渗透测试复现、WAF规则验证及防御策略制定提供可运行的技术支撑。1. 项目概述从零构建你的网络压力测试环境最近在折腾一些网络应用无论是自己写的Web服务还是给公司内部系统做性能摸底总绕不开一个问题这东西到底能扛住多少并发模拟真实用户请求看看服务在高负载下的表现这就是网络压力测试的核心。而“发包机”就是执行这项任务的专用工具或环境。它本质上是一台或多台配置好的机器运行着特定的脚本或程序能够按照预设的规则向目标服务器发起海量的网络请求数据包从而模拟出真实的访问压力。你可能听过JMeter、Locust这些大名鼎鼎的压力测试工具它们功能强大但配置繁琐环境依赖多。对于需要快速验证、定制化流量模型或者想在纯净的Linux环境下进行底层网络测试的场景一套轻量、可控、可脚本化定制的发包方案就显得尤为实用。这就是我们今天要搭建的“全套发包机”的价值所在——它不是一个单一的软件而是一个从系统准备、工具安装、脚本编写到执行监控的完整解决方案。尤其对于运维、开发和安全测试人员来说掌握这套方法意味着你拥有了随时对任何网络服务进行“压力体检”的能力。本教程将带你从一台干净的Linux服务器以Ubuntu 22.04为例开始逐步搭建起一个功能完整的发包环境。核心会围绕Shell脚本的编写展开因为Shell脚本是在Linux环境下实现自动化、定制化发包逻辑最直接、最高效的方式。我们会涉及基础命令工具的使用、循环与控制结构的编写、结果记录与分析最终形成一个可以一键执行、参数可调、结果可视化的自动化测试脚本集。无论你是想测试API接口的QPS每秒查询率还是验证Web服务器的并发连接处理能力这套方法都能为你提供一个坚实的起点。2. 核心工具链选型与底层原理搭建发包机工具选型是第一步。我们的目标是轻量、高效、系统原生支持或易于安装并且足够灵活以满足不同的测试场景。下面拆解几个核心组件及其背后的考量。2.1 网络请求生成器curl、ab、wrk与hping3发包的核心是生成HTTP或TCP/UDP请求。我们根据协议和复杂度分层选择curl(Client URL)这是我们的“瑞士军刀”。它支持数十种协议HTTP/HTTPS/FTP等功能极其丰富可以自定义请求头、方法、体、超时、重试等几乎所有HTTP参数。对于需要复杂交互、携带Cookie、处理重定向的API测试curl是不二之选。它的单次请求功能强大但原生不适合高并发需要结合Shell脚本的并发控制如后台执行或xargs -P来施展威力。ab(Apache Benchmark)Apache服务器自带的一个简单易用的HTTP基准测试工具。它的优势是开箱即用一条命令就能发起固定并发数的总请求量测试并直接输出汇总报告包括每秒请求数、请求时间分布等。缺点是功能相对单一无法灵活定制请求序列比如不同接口按比例混合且在高并发下其自身性能可能成为瓶颈。它适合做快速的、标准的HTTP性能摸底。wrk一个现代的、高性能的HTTP基准测试工具采用多线程事件驱动模型能用很少的系统资源产生巨大的压力。它支持通过Lua脚本来自定义请求、生成动态参数、处理响应灵活性远超ab。对于追求极致HTTP压测性能和灵活测试场景的开发者wrk是首选。本教程后续的高级脚本示例会引入wrk。hping3这是一个面向TCP/IP层的工具可以组装和发送任意自定义的原始TCP、UDP、ICMP数据包。它常用于网络安全领域的防火墙规则测试、端口扫描、MTU路径发现以及模拟各种网络攻击如SYN Flood。当我们测试的对象是四层负载均衡、防火墙策略或者需要进行协议栈层面的压力测试时hping3就派上用场了。请注意使用hping3进行压力测试务必在你自己拥有完全控制权的目标上进行绝对禁止对未经授权的任何网络目标发起测试这不仅是道德问题更可能触犯法律。选择逻辑对于绝大多数Web API和服务的压力测试curl脚本化和wrk的组合足以覆盖90%的场景。ab用于快速验证hping3用于更底层的网络测试。本教程将以curl脚本化作为主线因为它最能体现“搭建”和“定制”的过程并穿插介绍wrk的用法。2.2 系统监控与性能观测vmstat、sar、iftop发包机自身不能成为瓶颈同时我们也需要监控目标服务器的状态。因此监控工具必不可少。vmstat和sar(System Activity Reporter)用于监控发包机本身的系统资源。vmstat可以实时查看CPU、内存、IO和系统进程的整体状态快速判断系统负载。sar则更强大它能收集、报告和保存系统活动信息可以事后分析CPU利用率、内存使用、磁盘I/O、网络接口等历史数据。在长时间压测时用sar记录数据尤为重要它能帮你发现随着时间推移可能出现的资源耗尽问题如内存泄漏导致压测力度下降。iftop类似于top命令但是用于实时监控网络带宽。它可以显示当前服务器上各个网络连接的带宽使用情况一目了然地看出压测脚本产生的实际网络流量是否达到了预期以及是否有其他无关进程在占用带宽。实操心得在压测开始前先运行vmstat 1或sar -u 1观察一下系统空闲状态压测中对比观察。如果发包机的CPUus用户态或sy系统态利用率长时间接近100%或者waIO等待很高说明发包机本身可能已经成为瓶颈需要优化脚本或增加发包机节点分布式压测。2.3 结果收集与简单分析grep、awk、jq和ts压测会产生大量输出如何从中提取关键信息grep和awkShell文本处理的双子星。grep用于过滤出包含特定关键词如real、failed的行。awk则更强大可以按列处理数据例如计算所有请求耗时的平均值、最大值、成功率等。它们是Shell脚本中进行数据清洗和聚合的基石。jq如果测试的API返回的是JSON格式jq就是一个神器。它可以从JSON响应中快速提取某个字段的值用于后续的断言或统计。ts(来自moreutils包)一个给每行输出添加时间戳的小工具。在并发压测时日志是交错输出的有了时间戳你才能清晰地重建事件序列对于排查“什么时候开始出错”至关重要。工具安装命令# 对于基于Debian/Ubuntu的系统 sudo apt update sudo apt install -y curl apache2-utils wrk hping3 sysstat iftop jq moreutils # 对于基于RHEL/CentOS的系统 sudo yum install -y epel-release # 先安装EPEL仓库 sudo yum install -y curl httpd-tools wrk hping3 sysstat iftop jq moreutils安装后sar可能需要启用才能开始记录历史数据sudo systemctl enable sysstat sudo systemctl start sysstat。3. 基础Shell脚本编写从单次请求到并发循环理解了工具我们开始用Shell脚本将它们串联起来。Shell脚本的魅力在于它将简单的命令组合成强大的自动化流程。3.1 脚本安全与基础规范在写第一行代码前有两个至关重要的习惯脚本头每个Shell脚本开头都应该是#!/bin/bash指定解释器和set -euo pipefail。-e使得脚本中任何命令失败就立即退出-u遇到未定义的变量时报错-o pipefail确保管道命令中任意一个环节失败整个管道就视为失败。这能避免很多隐蔽的错误。变量使用对于可能包含空格或特殊字符的路径、URL引用变量时务必用双引号如$URL。使用${VAR}形式也更清晰和安全。一个标准的脚本模板如下#!/bin/bash set -euo pipefail # 定义变量 TARGET_URLhttp://your-api-endpoint.com/test REQUEST_COUNT100 CONCURRENCY10 LOG_FILEpressure_test_$(date %Y%m%d_%H%M%S).log # 函数定义 function send_request() { local url$1 curl -s -o /dev/null -w %{http_code}\t%{time_total}\n $url } # 主逻辑 echo 开始压测目标: $TARGET_URL | tee -a $LOG_FILE # ... 后续代码3.2 实现for循环与并发控制for循环是发起多次请求的核心结构。基础串行循环for ((i1; i$REQUEST_COUNT; i)); do echo 发起第 $i 次请求... curl -s http://目标地址 /dev/null done这种方式一次只发一个请求上一个结束才发下一个主要用于功能验证完全无法制造压力。引入并发后台任务for ((i1; i$REQUEST_COUNT; i)); do { curl -s -o /dev/null -w 请求$i: HTTP状态码:%{http_code}, 耗时:%{time_total}秒\n $TARGET_URL } done wait # 等待所有后台任务结束 echo 所有请求发送完毕。将curl命令放在{ } 中使其在子Shell中后台运行。这样所有请求几乎同时发起实现了并发。wait命令会阻塞直到所有后台进程都完成。这是最简单粗暴的并发方式但并发数不可控一次性启动所有任务可能瞬间耗尽系统资源或导致目标服务拒绝连接。使用命名管道(FIFO)和xargs控制并发度 更优雅的方式是控制同时进行的任务数量。这里介绍一种利用命名管道和xargs的方法# 创建一个命名管道 FIFO_FILE/tmp/$$.fifo mkfifo $FIFO_FILE # 将文件描述符6绑定到该管道 exec 6$FIFO_FILE rm -f $FIFO_FILE # 向管道中放入N个“令牌”N就是并发数 for ((i1; i$CONCURRENCY; i)); do echo 6 done echo 开始压测总请求数: $REQUEST_COUNT, 并发数: $CONCURRENCY for ((i1; i$REQUEST_COUNT; i)); do # 从管道读取一个令牌如果没有令牌则阻塞在这里 read -u6 { # 执行请求 HTTP_CODE$(curl -s -o /dev/null -w %{http_code} $TARGET_URL) TIME_TOTAL$(curl -s -o /dev/null -w %{time_total} $TARGET_URL) echo 请求$i: 状态码$HTTP_CODE, 耗时${TIME_TOTAL}s # 请求完成后将令牌放回管道 echo 6 } done wait # 等待所有后台进程 exec 6- # 关闭文件描述符6 echo 压测结束。这个脚本的精妙之处在于它通过管道里的“令牌”数量精确控制了最多只有$CONCURRENCY个curl进程同时运行。当一个请求完成它归还令牌新的请求才能获取令牌开始执行。这是实现可控并发的一个经典模式。使用GNU parallel或xargs -P 对于更简单的控制可以直接使用xargs的-P参数seq 1 $REQUEST_COUNT | xargs -n1 -P$CONCURRENCY -I{} curl -s -o /dev/null -w 请求{}: %{http_code}\n $TARGET_URLseq生成数字序列xargs的-P10表示最大10个进程并行-I{}用数字替换{}。这种方式更简洁但输出顺序可能会乱且错误处理不如上面的令牌桶方式精细。4. 构建一个完整的自动化压测脚本我们将上面学到的知识整合编写一个功能相对完整的压测脚本pressure_test.sh。这个脚本将包含参数化、并发控制、结果收集、简单统计和日志记录。4.1 脚本架构与参数解析一个好的脚本应该易于配置。我们使用命令行参数来传递关键配置。#!/bin/bash set -euo pipefail # 默认参数 TARGET_URL REQUEST_COUNT1000 CONCURRENCY50 TIMEOUT10 LOG_PREFIXpressure_test VERBOSEfalse # 帮助信息 function show_usage() { cat EOF 用法: $0 -u 目标URL [-c 并发数] [-n 总请求数] [-t 超时秒数] [-l 日志前缀] [-v] 参数: -u, --url 目标URL (必需) -c, --concurrency 并发连接数 (默认: 50) -n, --requests 总请求数 (默认: 1000) -t, --timeout 单个请求超时时间(秒) (默认: 10) -l, --log-prefix 日志文件前缀 (默认: pressure_test) -v, --verbose 显示详细输出 -h, --help 显示此帮助信息 示例: $0 -u http://api.example.com/health -c 20 -n 5000 EOF exit 0 } # 解析命令行参数 while [[ $# -gt 0 ]]; do case $1 in -u|--url) TARGET_URL$2 shift 2 ;; -c|--concurrency) CONCURRENCY$2 shift 2 ;; -n|--requests) REQUEST_COUNT$2 shift 2 ;; -t|--timeout) TIMEOUT$2 shift 2 ;; -l|--log-prefix) LOG_PREFIX$2 shift 2 ;; -v|--verbose) VERBOSEtrue shift ;; -h|--help) show_usage ;; *) echo 错误: 未知参数 $1 show_usage exit 1 ;; esac done # 检查必需参数 if [[ -z $TARGET_URL ]]; then echo 错误: 必须指定目标URL (-u) show_usage exit 1 fi # 创建日志目录和文件 LOG_DIR./logs mkdir -p $LOG_DIR TIMESTAMP$(date %Y%m%d_%H%M%S) LOG_FILE${LOG_DIR}/${LOG_PREFIX}_${TIMESTAMP}.log RESULT_FILE${LOG_DIR}/${LOG_PREFIX}_${TIMESTAMP}_result.txt echo | tee -a $LOG_FILE echo 压测开始时间: $(date) | tee -a $LOG_FILE echo 目标URL: $TARGET_URL | tee -a $LOG_FILE echo 总请求数: $REQUEST_COUNT | tee -a $LOG_FILE echo 并发数: $CONCURRENCY | tee -a $LOG_FILE echo 超时设置: ${TIMEOUT}s | tee -a $LOG_FILE echo | tee -a $LOG_FILE4.2 核心压测引擎与结果收集接下来是脚本的核心使用“令牌桶”模型实现并发控制并收集每个请求的结果。# 初始化统计变量 TOTAL_SUCCESS0 TOTAL_FAIL0 declare -a RESPONSE_TIMES # 用于存储响应时间的数组如果请求量巨大需注意内存 # 创建命名管道用于并发控制 FIFO_FILE/tmp/$$.fifo mkfifo $FIFO_FILE exec 6$FIFO_FILE rm -f $FIFO_FILE # 初始化令牌 for ((i0; iCONCURRENCY; i)); do echo 6 done echo 启动压测引擎... | tee -a $LOG_FILE START_TIME$(date %s.%N) # 主压测循环 for ((i1; iREQUEST_COUNT; i)); do read -u6 # 获取令牌 { # 使用curl发起请求并捕获输出 # -s: 静默模式不显示进度和错误信息 # -o /dev/null: 将响应体丢弃 # -w: 写入格式化输出HTTP状态码总时间建立连接时间开始传输时间 # --max-time: 超时设置 # --connect-timeout: 连接超时 CURL_OUTPUT$(curl -s -o /dev/null \ -w %{http_code}\t%{time_total}\t%{time_connect}\t%{time_starttransfer}\n \ --max-time $TIMEOUT \ --connect-timeout 5 \ $TARGET_URL 21) # 将标准错误也重定向到变量 CURL_EXIT_CODE$? HTTP_CODE$(echo $CURL_OUTPUT | awk {print $1}) TIME_TOTAL$(echo $CURL_OUTPUT | awk {print $2}) TIME_CONNECT$(echo $CURL_OUTPUT | awk {print $3}) TIME_STARTTRANSFER$(echo $CURL_OUTPUT | awk {print $4}) # 判断请求成功与否 (假设2xx和3xx状态码为成功) if [[ $CURL_EXIT_CODE -eq 0 $HTTP_CODE ~ ^[23][0-9][0-9]$ ]]; then STATUSSUCCESS ((TOTAL_SUCCESS)) RESPONSE_TIMES($TIME_TOTAL) # 记录成功请求的耗时 LOG_MSG请求#$i: 状态码$HTTP_CODE, 总耗时${TIME_TOTAL}s, 连接耗时${TIME_CONNECT}s, 传输开始耗时${TIME_STARTTRANSFER}s else STATUSFAIL ((TOTAL_FAIL)) LOG_MSG请求#$i: 失败! Curl退出码$CURL_EXIT_CODE, HTTP状态码$HTTP_CODE, 错误信息: $CURL_OUTPUT fi # 输出日志 if [[ $VERBOSE true || $STATUS FAIL ]]; then echo $LOG_MSG | tee -a $LOG_FILE else echo $LOG_MSG $LOG_FILE fi echo 6 # 归还令牌 } done wait # 等待所有后台进程结束 END_TIME$(date %s.%N) exec 6- # 关闭文件描述符 # 计算总耗时 TOTAL_DURATION$(echo $END_TIME - $START_TIME | bc) echo 所有请求完成总耗时: ${TOTAL_DURATION} 秒 | tee -a $LOG_FILE4.3 结果统计与报告生成压测结束后我们需要对收集的数据进行统计分析。# 计算成功率 SUCCESS_RATE$(echo scale2; $TOTAL_SUCCESS * 100 / $REQUEST_COUNT | bc) echo 压测结果统计 | tee -a $RESULT_FILE echo 总请求数: $REQUEST_COUNT | tee -a $RESULT_FILE echo 成功请求: $TOTAL_SUCCESS | tee -a $RESULT_FILE echo 失败请求: $TOTAL_FAIL | tee -a $RESULT_FILE echo 成功率: ${SUCCESS_RATE}% | tee -a $RESULT_FILE echo 总耗时: ${TOTAL_DURATION} 秒 | tee -a $RESULT_FILE echo 平均QPS: $(echo scale2; $REQUEST_COUNT / $TOTAL_DURATION | bc) | tee -a $RESULT_FILE # 计算响应时间统计仅统计成功的请求 if [[ ${#RESPONSE_TIMES[]} -gt 0 ]]; then # 将时间数组排序用于计算中位数和百分位数 IFS$\n SORTED_TIMES($(sort -n ${RESPONSE_TIMES[*]})) unset IFS COUNT${#SORTED_TIMES[]} # 计算平均值 SUM0 for t in ${SORTED_TIMES[]}; do SUM$(echo $SUM $t | bc) done AVG_TIME$(echo scale4; $SUM / $COUNT | bc) # 计算中位数 (50%) MID$((COUNT / 2)) if (( COUNT % 2 0 )); then MEDIAN$(echo scale4; (${SORTED_TIMES[MID-1]} ${SORTED_TIMES[MID]}) / 2 | bc) else MEDIAN${SORTED_TIMES[MID]} fi # 计算P90第90百分位数 P90_INDEX$(( (COUNT * 90 99) / 100 - 1 )) # 向上取整的索引计算 P90${SORTED_TIMES[$P90_INDEX]} # 计算P99第99百分位数 P99_INDEX$(( (COUNT * 99 99) / 100 - 1 )) P99${SORTED_TIMES[$P99_INDEX]} # 计算最小值和最大值 MIN_TIME${SORTED_TIMES[0]} MAX_TIME${SORTED_TIMES[COUNT-1]} echo 响应时间分析(单位:秒) | tee -a $RESULT_FILE echo 样本数(成功请求): $COUNT | tee -a $RESULT_FILE echo 平均响应时间: $AVG_TIME | tee -a $RESULT_FILE echo 最小响应时间: $MIN_TIME | tee -a $RESULT_FILE echo 最大响应时间: $MAX_TIME | tee -a $RESULT_FILE echo 中位数响应时间: $MEDIAN | tee -a $RESULT_FILE echo P90响应时间: $P90 | tee -a $RESULT_FILE echo P99响应时间: $P99 | tee -a $RESULT_FILE else echo 警告无成功请求无法计算响应时间统计。 | tee -a $RESULT_FILE fi echo | tee -a $RESULT_FILE echo 详细日志请查看: $LOG_FILE | tee -a $RESULT_FILE echo 本报告保存至: $RESULT_FILE | tee -a $RESULT_FILE echo 压测结束时间: $(date) | tee -a $LOG_FILE现在你已经拥有了一个功能完整的压测脚本。通过命令行调用它# 基本用法 bash pressure_test.sh -u http://192.168.1.100:8080/api/v1/test # 高级用法5000个请求100并发超时15秒并显示详细日志 bash pressure_test.sh -u http://your-service.com/endpoint -n 5000 -c 100 -t 15 -v -l my_test脚本会自动创建logs目录并在其中生成带有时间戳的详细日志文件和结果摘要文件。5. 高级技巧与场景扩展基础脚本能满足大部分需求但在复杂场景下我们还需要更多技巧。5.1 使用wrk进行高性能HTTP压测当需要产生极高的HTTP压力时用Shell启动成千上万个curl进程开销太大。此时wrk是更好的选择。它用C语言编写基于多线程和事件循环效率极高。一个简单的wrk命令如下wrk -t12 -c400 -d30s --latency http://目标地址-t12: 使用12个线程。-c400: 保持400个HTTP连接打开。-d30s: 持续压测30秒。--latency: 输出详细的延迟分布统计。但wrk的真正威力在于Lua脚本。你可以编写test.lua脚本-- 初始化阶段 function init(args) -- 可以在这里读取外部参数或初始化变量 math.randomseed(os.time()) end -- 每个线程初始化 function thread_init(thread_id) -- 每个线程独立的初始化比如分配不同的用户ID池 end -- 请求生成函数 request function() -- 动态生成路径或参数 local uid math.random(1000, 9999) local path /api/user/ .. uid -- 可以自定义请求头、方法、Body local headers {} headers[Content-Type] application/json headers[Authorization] Bearer fake_token local body string.format({query: user_%d}, uid) return wrk.format(POST, path, headers, body) end -- 响应处理函数可选 function response(status, headers, body) -- 可以在这里检查响应状态或内容进行自定义统计 if status ~ 200 then print(非200响应: .. status) end end然后运行wrk -t12 -c400 -d60s -s test.lua --latency http://目标地址通过Lua脚本你可以轻松实现参数化、混合场景不同接口按比例调用、请求依赖如先登录获取token等复杂逻辑。你可以将wrk命令集成到你的Shell脚本中用于执行特定场景的压测。5.2 模拟混合业务场景真实的用户流量不是单一的。我们可以编写一个调度脚本混合多种请求模式。#!/bin/bash # mixed_scenario.sh API_BASEhttp://your-service.com # 定义不同的API端点及其权重百分比 declare -A APIS( [/api/v1/get_info]60 # 60% 的请求是查询信息 [/api/v1/submit]30 # 30% 的请求是提交数据 [/api/v1/health]10 # 10% 的请求是健康检查 ) # 根据权重生成请求列表这里简化实际可按概率随机选择 REQUEST_LIST() for api in ${!APIS[]}; do weight${APIS[$api]} # 根据权重将API端点重复加入列表这是一种简单实现 for ((i0; iweight; i)); do REQUEST_LIST($API_BASE$api) done done TOTAL_REQUESTS1000 CONCURRENCY20 # 使用之前的令牌桶并发模型 FIFO_FILE/tmp/mixed_$$.fifo mkfifo $FIFO_FILE exec 6$FIFO_FILE rm -f $FIFO_FILE for ((i0; iCONCURRENCY; i)); do echo 6; done for ((i1; iTOTAL_REQUESTS; i)); do read -u6 { # 从请求列表中随机选取一个URL LIST_SIZE${#REQUEST_LIST[]} RANDOM_INDEX$(( RANDOM % LIST_SIZE )) TARGET_URL${REQUEST_LIST[$RANDOM_INDEX]} # 对于提交请求可以随机生成一些JSON数据 if [[ $TARGET_URL */submit ]]; then DATA$(printf {id: %d, value: test_%d} $RANDOM $RANDOM) curl -X POST -H Content-Type: application/json -d $DATA -s -o /dev/null -w %{http_code}\n $TARGET_URL else curl -s -o /dev/null -w %{http_code}\n $TARGET_URL fi echo 6 } done wait exec 6- echo 混合场景压测完成。这个脚本模拟了不同接口按权重分布的访问模式更贴近真实业务流量。5.3 分布式压测与协调单台发包机可能有性能瓶颈或网络限制。要产生更大压力需要多台机器协同工作。思路是一台控制机Master和多个压测机Agent。控制机脚本 (master.sh)#!/bin/bash # master.sh - 分发任务并汇总结果 AGENTS(agent1_ip agent2_ip agent3_ip) SCRIPTpressure_test.sh PARAMS-u http://target.com -n 2000 -c 50 RESULT_DIR./aggregated_results mkdir -p $RESULT_DIR for AGENT in ${AGENTS[]}; do echo 在 $AGENT 上启动压测... # 假设使用ssh密钥免密登录将脚本和参数传到Agent并执行 scp $SCRIPT $AGENT:/tmp/ ssh $AGENT bash /tmp/$SCRIPT $PARAMS -l ${AGENT}_test # 将后台进程ID记录下来方便后续等待 PIDS($!) done echo 等待所有Agent压测完成... for PID in ${PIDS[]}; do wait $PID done # 从各Agent收集结果日志 for AGENT in ${AGENTS[]}; do scp $AGENT:./logs/${AGENT}_test_*.log $RESULT_DIR/ 2/dev/null || true scp $AGENT:./logs/${AGENT}_test_*_result.txt $RESULT_DIR/ 2/dev/null || true done echo 所有Agent压测完成日志已收集至 $RESULT_DIR # 可以在这里添加一个汇总分析所有日志的脚本注意事项分布式压测需要解决时钟同步、结果去重、全局监控汇总等问题。更成熟的方案可以考虑使用Ansible进行批量部署和执行或者使用专门的分布式压测框架如Tsung。6. 常见问题、性能调优与安全警示在实际操作中你会遇到各种问题。这里记录一些典型的坑和解决方案。6.1 性能瓶颈排查清单当压测达不到预期压力时按以下顺序排查发包机自身资源CPU运行top或htop看%Cpu(s)行。如果us用户态或sy系统态长期高于80%说明CPU是瓶颈。对于Shell脚本并发大量进程系统调用开销(sy)可能很高。考虑减少并发数或换用wrk这类更高效的工具。内存通常不是主要瓶颈除非脚本有内存泄漏。用free -h查看。网络运行iftop或nload查看出口带宽是否已打满。千兆网卡的理论上限约125MB/s。如果打满考虑增加发包机或使用万兆网络。文件描述符每个网络连接、每个进程都会消耗文件描述符。用ulimit -n查看单进程限制用cat /proc/sys/fs/file-nr查看系统已用和总数。如果不够需要修改限制ulimit -n 65535临时或在/etc/security/limits.conf中永久修改。目标服务器状态通过监控工具如目标服务器的vmstat,iostat,netstat观察其CPU、内存、磁盘IO和网络连接数。如果目标服务器的资源使用率很低但你的压测QPS上不去问题可能出在网络链路上或客户端配置上。检查目标服务的日志看是否有大量错误如连接拒绝、超时。网络链路问题延迟和丢包用ping和mtr或traceroute检查到目标服务器的网络质量。高延迟或丢包会严重限制有效吞吐量。连接数限制检查目标服务器的防火墙、负载均衡器或服务本身如Nginx的worker_connectionsLinux的net.core.somaxconn是否有连接数限制。6.2 脚本执行中的典型错误与处理错误现象可能原因解决方案bash: ./test.sh: Permission denied脚本没有执行权限chmod x test.sh-bash: ./test.sh: /bin/bash^M: bad interpreter脚本在Windows下编辑行尾是CRLF使用dos2unix test.sh转换或用sed -i s/\r$// test.shcurl: (7) Failed to connect to host port ...网络不通、目标服务未启动、防火墙阻止检查网络连通性(telnet host port)、服务状态和防火墙规则curl: (28) Operation timed out after ...连接超时或服务器响应太慢增加--connect-timeout和--max-time参数或检查服务器负载脚本启动大量进程后系统变卡甚至无响应并发进程数过多耗尽系统资源使用“令牌桶”或xargs -P严格控制并发数或换用wrk压测一段时间后成功率骤降目标服务器或中间件连接池耗尽、内存泄漏降低压测强度观察服务器监控指标检查服务日志too many open files系统或进程打开文件数超限使用ulimit -n查看并修改限制如ulimit -n 655356.3 至关重要的安全与法律警示这是搭建和使用发包机必须时刻牢记的底线。警告压力测试是一把双刃剑。不当使用等同于网络攻击。明确授权只对你拥有完全所有权和控制权的目标进行测试。这包括你自己开发并部署在本地或私有云的服务。公司内部明确授权你进行压测的预发布或生产环境必须有书面或邮件授权。第三方提供的、明确允许进行压力测试的公开服务如某些云服务商提供的测试端点。绝对禁止严禁对任何互联网上未经明确授权的网站、API、服务进行压力测试。这属于“拒绝服务DoS”攻击的范畴是违法行为。严禁使用本教程中的方法进行任何形式的“抢票”、“刷单”、“秒杀”脚本编写或对商业网站进行恶意请求。这不仅不道德还可能涉及计算机信息系统犯罪。严禁在脚本中尝试绕过任何安全机制如验证码、频率限制。伦理与最佳实践控制范围在测试前明确测试时间窗口并通知可能受影响的相关方如运维、其他开发人员。循序渐进不要一开始就上最大压力。从一个很低的并发数开始逐步增加观察系统表现。这有助于你发现性能拐点而不是直接冲垮服务。监控与止损压测时密切监控目标系统的核心指标CPU、内存、响应时间、错误率。一旦发现服务不可用或核心业务受损立即停止压测。清理现场测试结束后确保脚本完全停止没有残留进程在后台继续发送请求。搭建发包机、编写自动化脚本是一项强大的技能它能帮助你更好地理解系统行为构建更健壮的服务。但请务必带着责任感和法律意识来使用这项技能让它成为保障系统稳定的工具而非破坏秩序的武器。本文还有配套的精品资源点击获取
返回列表