Envoy与Nginx正向代理压测方案
目录
目标
- 对比 Envoy 与 Nginx 在正向代理场景下的吞吐、延迟、失败率与连接行为(TIME_WAIT)。
环境
- Envoy:监听
9094,管理口9902,启用来源/目标 RBAC、动态前向代理(c-ares DNS)、访问日志与本地限流。 - Nginx:监听
8080,启用 HTTP/1.1 长连接与reuseport、CONNECT 支持,变量上游转发。 - 系统(Linux 参考):
ip_local_port_range=20000–65535、tcp_tw_reuse=1、tcp_timestamps=1、tcp_max_tw_buckets=200000。
指标采集
- 吞吐与延迟:QPS、平均耗时、P50/P90/P99。
- 失败率:HTTP 4xx/5xx 比例、连接错误(如
connect() failed)。 - 连接行为:
TIME_WAIT总量与趋势。 - 代理内部指标:
- Envoy:
curl http://localhost:9902/stats | head -n 200,关注cluster.dynamic_forward_proxy_cluster.*、dns_cache.*、local_ratelimit.*、http.*。 - Nginx:访问日志与错误日志,统计 5xx 与连接失败。
- Envoy:
压测命令
- HTTP(Envoy):
docker run --rm rakyll/hey -z 60s -c 200 -x http://host.docker.internal:9094 http://example.org/
- HTTP(Nginx):
docker run --rm rakyll/hey -z 60s -c 200 -x http://host.docker.internal:8080 http://example.org/
- HTTPS(CONNECT)功能验证(并发 curl):
docker run --rm curlimages/curl:8.5.0 -sS --proxy http://host.docker.internal:9094 https://ifconfig.io
TIME_WAIT 采样
- macOS:
watch -n 5 'netstat -an | grep TIME_WAIT | wc -l' - Linux:
watch -n 5 'ss -tan state time-wait | wc -l'
输出记录模板
- 工具命令、QPS、平均耗时、P95/P99、失败率、
TIME_WAIT初值/峰值/稳态值、Envoy/Nginx关键指标快照。
一键脚本
- 路径:
scripts/run_benchmark.sh - 使用:
bash scripts/run_benchmark.sh - 可选参数(环境变量):
DURATION压测时长秒(默认60)CONCURRENCY并发数(默认200)TARGETHTTP目标(默认http://example.org/)ENVOY_PROXY(默认http://host.docker.internal:9094)NGINX_PROXY(默认http://host.docker.internal:8080)CONNECT_TARGET(默认https://ifconfig.io)CONNECT_COUNT(默认50)CONNECT_PARALLEL(默认10)
- 输出目录:
docs/results/<timestamp>/,包含 hey 输出、TIME_WAIT 采样、Envoy stats 快照与 CONNECT 结果。
结论预期
- Envoy:动态前向代理与连接合并带来更高复用率;在大量不同上游域名场景下,
TIME_WAIT峰值与稳态值更低,失败率更低,P99更稳。 - Nginx:变量上游难以池化复用,可能导致频繁建连与大量
TIME_WAIT,高并发下更易受端口耗尽影响。
风险与注意
- 白名单:测试目标域必须在 Envoy 白名单内,否则会被 RBAC 返回 403。
- CONNECT:压测工具有限,建议以功能验证与失败率统计为主,配合 HTTP 压测综合判断。
- 正则复杂度:避免单条 RE2 规则过大;当前已拆分并使用低复杂度通配(
*.{region}.log.aliyuncs.com)。
可执行指引(一步步)
前置条件
- 安装 Docker(macOS 可用 Docker Desktop)。
- 仓库已存在 Envoy 配置:
envoy/envoy-forward-proxy.yaml。
启动 Envoy 容器
docker rm -f envoy-forward-proxy || truedocker run -d --name envoy-forward-proxy -p 9094:9094 -p 9902:9902 -v $(pwd)/envoy/envoy-forward-proxy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy:v1.30.2- 验证管理接口:
curl -sS http://localhost:9902/stats | head -n 20 - 验证白名单域:
- HTTP:
docker run --rm curlimages/curl:8.5.0 -v --proxy http://host.docker.internal:9094 http://example.org/ - HTTPS:
docker run --rm curlimages/curl:8.5.0 -v --proxy http://host.docker.internal:9094 https://ifconfig.io - 阿里云日志域(已通配允许):
docker run --rm curlimages/curl:8.5.0 -v --proxy http://host.docker.internal:9094 http://sl-store-sdk-fjny1.ap-southeast-1.log.aliyuncs.com/ - 非白名单示例(应返回 403):
docker run --rm curlimages/curl:8.5.0 -v --proxy http://host.docker.internal:9094 http://httpbin.org/ip
- HTTP:
启动(或跳过)Nginx 正向代理
- 若本机已运行 Nginx 正向代理(监听
8080,具备ngx_http_proxy_connect_module):- 健康检查:
curl -sS http://localhost:8081/health - HTTP 验证:
docker run --rm curlimages/curl:8.5.0 -v --proxy http://host.docker.internal:8080 http://example.org/
- 健康检查:
- 如果未安装带 CONNECT 模块的 Nginx,可暂时只对比 Envoy(HTTP/HTTPS),Nginx 对比仅进行 HTTP(如你已有其他 HTTP 代理)。
- 若本机已运行 Nginx 正向代理(监听
运行压测脚本
- 默认:
bash scripts/run_benchmark.sh - 自定义时长/并发:
DURATION=120 CONCURRENCY=300 bash scripts/run_benchmark.sh - 自定义目标与代理:
TARGET=http://example.org/ ENVOY_PROXY=http://host.docker.internal:9094 NGINX_PROXY=http://host.docker.internal:8080 bash scripts/run_benchmark.sh - 脚本结束会打印输出目录,如:
docs/results/20251128-081500
- 默认:
查看结果
- Envoy:
envoy_http_hey.txt、envoy_timewait.csv、envoy_stats_after_http.txt、envoy_connect_results.txt、envoy_stats_after_connect.txt - Nginx:
nginx_http_hey.txt、nginx_timewait.csv - 观察对比:
- QPS 与 P99 延迟(hey 输出)
TIME_WAIT趋势(CSV,可导入 Excel/Numbers 画折线图)- Envoy 指标(DNS 缓存、连接池、限流)
- Envoy:
常见故障与处理
- 代理 403:目标域名不在白名单或命中敏感 IP 阻断(检查
envoy/envoy-forward-proxy.yaml:101–161)。 - DNS 解析失败:检查本地网络、DNS 服务器(配置在
envoy/envoy-forward-proxy.yaml:176–183, 224–231)。 - Nginx CONNECT 不工作:需使用包含
ngx_http_proxy_connect_module的 Nginx 构建或镜像;否则仅能进行 HTTP 对比。
构建带 CONNECT 模块的 Nginx(Docker)
- Dockerfile 路径:
docker/nginx-connect/Dockerfile - 构建镜像:
docker build -t nginx-connect:1.24.0 -f docker/nginx-connect/Dockerfile .
- 运行容器(挂载当前仓库 Nginx 配置):
docker rm -f nginx-forward-proxy || truedocker run -d --name nginx-forward-proxy -p 8080:8080 -p 8081:8081 \ -v $(pwd)/log/nginx.conf:/usr/local/nginx/conf/nginx.conf \ -v $(pwd)/log/nginx_deploy_download.conf:/usr/local/nginx/conf/nginx_deploy_download.conf \ nginx-connect:1.24.0
- 验证:
- 健康检查:
curl -sS http://localhost:8081/health - HTTP:
docker run --rm curlimages/curl:8.5.0 -v --proxy http://host.docker.internal:8080 http://example.org/ - HTTPS(CONNECT):
docker run --rm curlimages/curl:8.5.0 -v --proxy http://host.docker.internal:8080 https://ifconfig.io
- 健康检查:
Dockerfile
| |
压测脚本(支持容器内TIME_WAIT采样与并发自动推导)
| |
启用并发自动推导
| |
脚本将:
- 从 Nginx
stub_status读取Reading/Writing/Active connections; - 估算并发
derived = (Reading + Writing) + 20(低并发)或+ 20%(高并发),并写入derive_concurrency.log; - 然后以推导并发运行压测。
| |