feat(benchmark): enhance dev.compose.yml with benchmark services and scripts

- Added benchmark services (whoami, godoxy, traefik, caddy, nginx) to dev.compose.yml.
- Introduced a new benchmark.sh script for load testing using wrk and h2load.
- Updated Makefile to include a benchmark target for easy execution of the new script.
This commit is contained in:
yusing
2026-01-03 00:28:59 +08:00
parent 587b83cf14
commit dc8abe943d
3 changed files with 331 additions and 1 deletions

View File

@@ -123,6 +123,11 @@ dev:
dev-build: build
docker compose -f dev.compose.yml up -t 0 -d app --force-recreate
benchmark:
@docker compose -f dev.compose.yml up -d --force-recreate whoami godoxy traefik caddy nginx
sleep 1
@./scripts/benchmark.sh
dev-run: build
cd dev-data && ${BIN_PATH}
@@ -142,7 +147,7 @@ ci-test:
act -n --artifact-server-path /tmp/artifacts -s GITHUB_TOKEN="$$(gh auth token)"
cloc:
scc -w -i go --not-match '_test.go$'
scc -w -i go --not-match '_test.go$$'
push-github:
git push origin $(shell git rev-parse --abbrev-ref HEAD)

View File

@@ -1,3 +1,8 @@
x-benchmark: &benchmark
restart: no
labels:
proxy.exclude: true
proxy.#1.healthcheck.disable: true
services:
app:
image: godoxy-dev
@@ -90,7 +95,148 @@ services:
labels:
proxy.#1.scheme: h2c
proxy.#1.port: 80
whoami:
<<: *benchmark
image: traefik/whoami:latest
container_name: whoami
godoxy:
<<: *benchmark
build: .
container_name: godoxy-benchmark
environment:
DOCKER_HOST: unix:///var/run/docker.sock
ports:
- 8080:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
configs:
- source: godoxy_config
target: /app/config/config.yml
- source: godoxy_provider
target: /app/config/providers.yml
traefik:
<<: *benchmark
image: traefik:latest
container_name: traefik
command:
- --api.insecure=true
- --entrypoints.web.address=:8081
- --providers.file.directory=/etc/traefik/dynamic
- --providers.file.watch=true
- --log.level=ERROR
ports:
- 8081:8081
configs:
- source: traefik_config
target: /etc/traefik/dynamic/routes.yml
caddy:
<<: *benchmark
image: caddy:latest
container_name: caddy
ports:
- 8082:80
configs:
- source: caddy_config
target: /etc/caddy/Caddyfile
tmpfs:
- /data
- /config
nginx:
<<: *benchmark
image: nginx:latest
container_name: nginx
command: nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
ports:
- 8083:80
configs:
- source: nginx_config
target: /etc/nginx/nginx.conf
configs:
godoxy_config:
content: |
providers:
include:
- providers.yml
godoxy_provider:
content: |
whoami:
host: whoami
traefik_config:
content: |
http:
routers:
whoami:
rule: "Host(`whoami.domain.com`)"
entryPoints:
- web
service: whoami
services:
whoami:
loadBalancer:
servers:
- url: "http://whoami:80"
caddy_config:
content: |
{
admin off
auto_https off
default_bind 0.0.0.0
servers {
protocols h2c h1
}
}
http://whoami.domain.com:80 {
reverse_proxy whoami:80
}
nginx_config:
content: |
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /dev/null;
pid /var/run/nginx.pid;
events {
worker_connections 10240;
multi_accept on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 10000;
upstream backend {
server whoami:80;
keepalive 128;
}
server {
listen 80;
server_name whoami.domain.com;
http2 on;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $$host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_buffering off;
}
}
}
parca:
content: |
object_storage:

179
scripts/benchmark.sh Normal file
View File

@@ -0,0 +1,179 @@
#!/bin/bash
# Benchmark script to compare GoDoxy, Traefik, Caddy, and Nginx
# Uses wrk for HTTP load testing
set -e
# Configuration
HOST="whoami.domain.com"
DURATION="10s"
THREADS=4
CONNECTIONS=100
# Color functions for output
red() { echo -e "\033[0;31m$*\033[0m"; }
green() { echo -e "\033[0;32m$*\033[0m"; }
yellow() { echo -e "\033[1;33m$*\033[0m"; }
blue() { echo -e "\033[0;34m$*\033[0m"; }
# Check if wrk is installed
if ! command -v wrk &> /dev/null; then
red "Error: wrk is not installed"
echo "Please install wrk:"
echo " Ubuntu/Debian: sudo apt-get install wrk"
echo " macOS: brew install wrk"
echo " Or build from source: https://github.com/wg/wrk"
exit 1
fi
if ! command -v h2load &> /dev/null; then
red "Error: h2load is not installed"
echo "Please install h2load (nghttp2-client):"
echo " Ubuntu/Debian: sudo apt-get install nghttp2-client"
echo " macOS: brew install nghttp2"
exit 1
fi
OUTFILE="/tmp/reverse_proxy_benchmark_$(date +%Y%m%d_%H%M%S).log"
: > "$OUTFILE"
exec > >(tee -a "$OUTFILE") 2>&1
blue "========================================"
blue "Reverse Proxy Benchmark Comparison"
blue "========================================"
echo ""
echo "Target: $HOST"
echo "Duration: $DURATION"
echo "Threads: $THREADS"
echo "Connections: $CONNECTIONS"
echo ""
# Define services to test
declare -A services=(
["GoDoxy"]="http://127.0.0.1:8080/bench"
["Traefik"]="http://127.0.0.1:8081/bench"
["Caddy"]="http://127.0.0.1:8082/bench"
["Nginx"]="http://127.0.0.1:8083/bench"
)
# Array to store connection errors
declare -a connection_errors=()
# Function to test connection before benchmarking
test_connection() {
local name=$1
local url=$2
yellow "Testing connection to $name..."
# Test HTTP/1.1
local res1=$(curl -sS -w "\n%{http_code}" --http1.1 -H "Host: $HOST" --max-time 5 "$url")
local body1=$(echo "$res1" | head -n -1)
local status1=$(echo "$res1" | tail -n 1)
# Test HTTP/2
local res2=$(curl -sS -w "\n%{http_code}" --http2-prior-knowledge -H "Host: $HOST" --max-time 5 "$url")
local body2=$(echo "$res2" | head -n -1)
local status2=$(echo "$res2" | tail -n 1)
local failed=false
if [ "$status1" != "200" ] || [ "$body1" != "1" ]; then
red "$name failed HTTP/1.1 connection test (Status: $status1, Body: $body1)"
failed=true
fi
if [ "$status2" != "200" ] || [ "$body2" != "1" ]; then
red "$name failed HTTP/2 connection test (Status: $status2, Body: $body2)"
failed=true
fi
if [ "$failed" = true ]; then
connection_errors+=("$name failed connection test (URL: $url)")
return 1
else
green "$name is reachable (HTTP/1.1 & HTTP/2)"
return 0
fi
}
blue "========================================"
blue "Connection Tests"
blue "========================================"
echo ""
# Run connection tests for all services
for name in "${!services[@]}"; do
test_connection "$name" "${services[$name]}"
done
echo ""
blue "========================================"
# Exit if any connection test failed
if [ ${#connection_errors[@]} -gt 0 ]; then
echo ""
red "Connection test failed for the following services:"
for error in "${connection_errors[@]}"; do
red " - $error"
done
echo ""
red "Please ensure all services are running before benchmarking"
exit 1
fi
echo ""
green "All services are reachable. Starting benchmarks..."
echo ""
blue "========================================"
echo ""
# Function to run benchmark
run_benchmark() {
local name=$1
local url=$2
local h2_duration="${DURATION%s}"
yellow "Testing $name..."
echo "========================================"
echo "$name"
echo "URL: $url"
echo "========================================"
echo ""
echo "[HTTP/1.1] wrk"
wrk -t"$THREADS" -c"$CONNECTIONS" -d"$DURATION" \
-H "Host: $HOST" \
"$url"
echo ""
echo "[HTTP/2] h2load"
h2load -t"$THREADS" -c"$CONNECTIONS" --duration="$h2_duration" \
-H "Host: $HOST" \
-H ":authority: $HOST" \
"$url" | grep -vE "^(starting benchmark...|spawning thread #|progress: |Warm-up )"
echo ""
green "$name benchmark completed"
blue "----------------------------------------"
echo ""
}
# Run benchmarks for each service
for name in "${!services[@]}"; do
run_benchmark "$name" "${services[$name]}"
done
blue "========================================"
blue "Benchmark Summary"
blue "========================================"
echo ""
echo "All benchmark output saved to: $OUTFILE"
echo ""
echo "Key metrics to compare:"
echo " - Requests/sec (throughput)"
echo " - Latency (mean, stdev)"
echo " - Transfer/sec"
echo ""
green "All benchmarks completed!"