CI/CD 管道中的自动负载测试:来自自定义 Bash 脚本的经验教训
简介:通过自动负载测试避免 Web 应用程序性能漏洞
让我们面对现实,性能问题可能会使您的 Web 应用程序变得像《权力的游戏》中乔佛里·拜拉席恩的角色一样棘手——没有人喜欢它。
在 Etsy,他们的工程师非常了解这一点,并决定采取主动行动。他们决定编写自己的自定义 Bash 脚本,将其无缝集成到他们的 CI/CD 管道中,而不是依赖现成的工具进行负载测试。这就像创建自己的盔甲,完美满足您的应用程序需求。
让我们一起努力,共同创造一些有影响力的东西!
在本文中,我们将探讨:
无论您是 DevOps 新手,还是正在寻找将性能测试集成到工作流程中的创新方法,本文都提供了见解、实际示例和协作空间。让我们一起深入研究并共同构建一些有影响力的东西。
负载测试脚本
优化 Web 应用程序的性能通常需要在灵活性、功能性和资源消耗之间做出妥协。现成的负载测试工具提供了许多功能,但它们在设置、自定义和资源使用方面通常会带来很大的开销。
为什么要使用自定义脚本?
在许多情况下,轻量级、专用解决方案的灵活性优于功能繁多的选项。例如:
**脚本的功能**
该脚本旨在处理负载测试的关键方面,同时保持用户友好性并适应各种用例。它提供以下功能:
**1. 输入处理**
该脚本接受三个基本参数:
目标 URL:要测试的 Web 应用程序端点。
并发度:同时发送的请求数。
测试时长:测试运行的时间(以秒为单位)。
validate_inputs() { local url=$1 local concurrent=$2 local duration=$3 if [[ ! $url =~ ^https?:// ]]; then echo "Error: Invalid URL format. Must start with http:// or https://" exit 1 fi if ! [[ "$concurrent" =~ ^[0-9]+$ ]] || [ "$concurrent" -lt 1 ]; then echo "Error: Concurrent requests must be a positive number" exit 1 fi if ! [[ "$duration" =~ ^[0-9]+$ ]] || [ "$duration" -lt 1 ]; then echo "Error: Duration must be a positive number" exit 1 fi }
为什么这很重要?
验证输入可确保脚本不会因参数无效而崩溃或产生不准确的结果。这是一个简单但必不可少的稳健性步骤。
**2. 指标收集**
该脚本使用 Apache Benchmark(ab)执行负载测试,收集以下指标:
总请求数:测试期间发送的请求数。
失败的请求:由于超时或服务器错误而失败的请求数。
响应时间:包括平均响应时间和最大响应时间。
成功率:成功请求占总请求的百分比。
结果以 JSON 格式记录,以便于与监控工具集成:
cat > "$log_file" << EOF { "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", "url": "$url", "configuration": { "concurrent_requests": $concurrent, "duration": $duration }, "results": { "total_requests": $total_requests, "failed_requests": $failed_requests, "success_rate": $(echo "scale=2; ($total_requests-$failed_requests)/$total_requests*100" | bc), "mean_response_time": $mean_time, "max_response_time": $max_time } } EOF
输出示例;
{ "timestamp": "2024-12-14T12:00:00Z", "url": "https://example.com", "configuration": { "concurrent_requests": 10, "duration": 60 }, "results": { "total_requests": 600, "failed_requests": 5, "success_rate": 99.17, "mean_response_time": 200, "max_response_time": 1000 } }
**3. 日志记录**
该脚本为每次测试运行生成一个唯一的日志文件,并将结果存储在专用目录中:
setup_logging() { local timestamp=$(date +%Y%m%d_%H%M%S) local results_dir="load_test_results" mkdir -p "$results_dir" echo "${results_dir}/load_test_${timestamp}.json" }
因此,这之所以重要是为了组织日志,从而轻松比较多次测试运行的结果,从而实现趋势分析。
local total_requests=$(grep "Complete requests:" "${log_file%.json}_raw.txt" | awk '{print $3}') local mean_time=$(grep "Mean:" "${log_file%.json}_raw.txt" | awk '{print $4}')
运行脚本的方法如下
`./main.sh https://example.com 10 60
`
Jenkins Pipeline:自动化负载测试
Jenkins 是自动化 DevOps 工作流程的强大工具。凭借其灵活性,负载测试等重复性任务可以自动化并无缝集成到软件开发生命周期中。对于这个项目,Jenkins 不仅可以自动执行我们的自定义负载测试脚本,还可以毫不费力地处理结果存档和工作区清理。
**管道的主要特点**
以下是管道设计如何运作的简要概述:
完整的 Jenkinsfile 以及解释每个阶段的详细注释可在我的 GitHub 存储库中找到。点击此处查看
悬而未决的问题
有趣的是,当我写这篇文章时,我开始思考——我们能否让这个管道更加智能?这时我想到了 SonarQube。但它甚至可以与 Bash 脚本一起使用吗?我很想听听你的想法!