178 lines
6.1 KiB
Bash
Executable File
178 lines
6.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Grok2API 并发测试脚本(Shell版本)
|
|
# 使用 curl 和 GNU parallel 进行并发测试
|
|
|
|
set -e
|
|
|
|
# 配置
|
|
BASE_URL="${BASE_URL:-http://localhost:8001}"
|
|
API_KEY="${API_KEY:-}"
|
|
CONCURRENCY="${CONCURRENCY:-10}"
|
|
TOTAL_REQUESTS="${TOTAL_REQUESTS:-50}"
|
|
|
|
# 颜色
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${BLUE}╔══════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${BLUE}║ Grok2API 并发性能测试工具 (Shell版) ║${NC}"
|
|
echo -e "${BLUE}╚══════════════════════════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}🔗 测试目标:${NC} $BASE_URL"
|
|
echo -e "${GREEN}🔑 API Key:${NC} ${API_KEY:-(未设置)}"
|
|
echo -e "${GREEN}📊 并发数:${NC} $CONCURRENCY"
|
|
echo -e "${GREEN}📈 总请求数:${NC} $TOTAL_REQUESTS"
|
|
echo ""
|
|
|
|
# 检查依赖
|
|
if ! command -v curl &> /dev/null; then
|
|
echo -e "${RED}❌ 错误: 需要安装 curl${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# 创建临时目录
|
|
TMP_DIR=$(mktemp -d)
|
|
trap "rm -rf $TMP_DIR" EXIT
|
|
|
|
# 单个请求函数
|
|
test_request() {
|
|
local request_id=$1
|
|
local start_time=$(date +%s.%N)
|
|
|
|
# 构建请求
|
|
local headers="Content-Type: application/json"
|
|
if [ -n "$API_KEY" ]; then
|
|
headers="${headers}\nAuthorization: Bearer ${API_KEY}"
|
|
fi
|
|
|
|
local response=$(curl -s -w "\n%{http_code}\n%{time_total}" \
|
|
-X POST "${BASE_URL}/v1/chat/completions" \
|
|
-H "Content-Type: application/json" \
|
|
${API_KEY:+-H "Authorization: Bearer $API_KEY"} \
|
|
-d "{
|
|
\"model\": \"grok-3-fast\",
|
|
\"messages\": [{\"role\": \"user\", \"content\": \"测试请求 #${request_id},请简短回复OK\"}],
|
|
\"stream\": false,
|
|
\"max_tokens\": 10
|
|
}" 2>&1)
|
|
|
|
local http_code=$(echo "$response" | tail -n 2 | head -n 1)
|
|
local time_total=$(echo "$response" | tail -n 1)
|
|
|
|
# 记录结果
|
|
echo "${request_id},${http_code},${time_total}" >> "$TMP_DIR/results.csv"
|
|
|
|
# 显示进度
|
|
echo -ne "\r 进度: ${request_id}/${TOTAL_REQUESTS}"
|
|
}
|
|
|
|
# 导出函数供 parallel 使用
|
|
export -f test_request
|
|
export BASE_URL API_KEY TMP_DIR
|
|
|
|
# 清空结果文件
|
|
echo "id,status,time" > "$TMP_DIR/results.csv"
|
|
|
|
echo -e "${YELLOW}🚀 开始并发测试...${NC}"
|
|
START_TIME=$(date +%s.%N)
|
|
|
|
# 使用 GNU parallel(如果可用),否则使用简单循环
|
|
if command -v parallel &> /dev/null; then
|
|
seq 1 $TOTAL_REQUESTS | parallel -j $CONCURRENCY test_request {}
|
|
else
|
|
# 简单的后台任务并发
|
|
for i in $(seq 1 $TOTAL_REQUESTS); do
|
|
test_request $i &
|
|
|
|
# 控制并发数
|
|
if (( i % CONCURRENCY == 0 )); then
|
|
wait
|
|
fi
|
|
done
|
|
wait
|
|
fi
|
|
|
|
END_TIME=$(date +%s.%N)
|
|
TOTAL_TIME=$(echo "$END_TIME - $START_TIME" | bc)
|
|
|
|
echo -e "\n"
|
|
|
|
# 统计结果
|
|
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${BLUE}📈 测试结果统计${NC}"
|
|
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
# 统计成功/失败
|
|
SUCCESS_COUNT=$(awk -F',' '$2 == 200 {count++} END {print count+0}' "$TMP_DIR/results.csv")
|
|
ERROR_COUNT=$((TOTAL_REQUESTS - SUCCESS_COUNT))
|
|
|
|
echo -e " 测试时间: ${TOTAL_TIME}s"
|
|
echo -e " 总请求数: ${TOTAL_REQUESTS}"
|
|
echo -e " 并发数: ${CONCURRENCY}"
|
|
echo ""
|
|
echo -e " 成功请求: ${GREEN}${SUCCESS_COUNT}${NC} ($(echo "scale=1; $SUCCESS_COUNT * 100 / $TOTAL_REQUESTS" | bc)%)"
|
|
echo -e " 失败请求: ${RED}${ERROR_COUNT}${NC} ($(echo "scale=1; $ERROR_COUNT * 100 / $TOTAL_REQUESTS" | bc)%)"
|
|
echo ""
|
|
|
|
# 计算吞吐量
|
|
THROUGHPUT=$(echo "scale=2; $TOTAL_REQUESTS / $TOTAL_TIME" | bc)
|
|
echo -e " 吞吐量: ${GREEN}${THROUGHPUT}${NC} req/s"
|
|
echo ""
|
|
|
|
# 延迟统计(只统计成功的请求)
|
|
if [ $SUCCESS_COUNT -gt 0 ]; then
|
|
echo -e " 延迟统计:"
|
|
|
|
# 提取成功请求的延迟时间
|
|
awk -F',' '$2 == 200 {print $3}' "$TMP_DIR/results.csv" | sort -n > "$TMP_DIR/latencies.txt"
|
|
|
|
MIN=$(head -n 1 "$TMP_DIR/latencies.txt" | awk '{printf "%.0f", $1*1000}')
|
|
MAX=$(tail -n 1 "$TMP_DIR/latencies.txt" | awk '{printf "%.0f", $1*1000}')
|
|
AVG=$(awk '{sum+=$1; count++} END {printf "%.0f", sum/count*1000}' "$TMP_DIR/latencies.txt")
|
|
|
|
# P50
|
|
P50_LINE=$((SUCCESS_COUNT / 2))
|
|
P50=$(sed -n "${P50_LINE}p" "$TMP_DIR/latencies.txt" | awk '{printf "%.0f", $1*1000}')
|
|
|
|
# P95
|
|
P95_LINE=$(echo "scale=0; $SUCCESS_COUNT * 0.95 / 1" | bc)
|
|
P95=$(sed -n "${P95_LINE}p" "$TMP_DIR/latencies.txt" | awk '{printf "%.0f", $1*1000}')
|
|
|
|
# P99
|
|
P99_LINE=$(echo "scale=0; $SUCCESS_COUNT * 0.99 / 1" | bc)
|
|
P99=$(sed -n "${P99_LINE}p" "$TMP_DIR/latencies.txt" | awk '{printf "%.0f", $1*1000}')
|
|
|
|
echo -e " 最小: ${MIN}ms"
|
|
echo -e " 平均: ${AVG}ms"
|
|
echo -e " 最大: ${MAX}ms"
|
|
echo -e " P50: ${P50}ms"
|
|
echo -e " P95: ${P95}ms"
|
|
echo -e " P99: ${P99}ms"
|
|
fi
|
|
|
|
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
# 性能评级
|
|
echo -e "${YELLOW}🎯 性能评级:${NC}"
|
|
|
|
if (( $(echo "$THROUGHPUT >= 100" | bc -l) )); then
|
|
RATING="⭐⭐⭐⭐⭐ 优秀"
|
|
elif (( $(echo "$THROUGHPUT >= 60" | bc -l) )); then
|
|
RATING="⭐⭐⭐⭐ 良好"
|
|
elif (( $(echo "$THROUGHPUT >= 30" | bc -l) )); then
|
|
RATING="⭐⭐⭐ 中等"
|
|
elif (( $(echo "$THROUGHPUT >= 10" | bc -l) )); then
|
|
RATING="⭐⭐ 较低"
|
|
else
|
|
RATING="⭐ 需优化"
|
|
fi
|
|
|
|
echo -e " 吞吐量 (${THROUGHPUT} req/s): ${RATING}"
|
|
|
|
echo ""
|
|
echo -e "${GREEN}✅ 测试完成!${NC}"
|