性能调优
先测量,别先调
章节「先测量,别先调」example.com { metrics { handle /metrics } reverse_proxy localhost:3000}关键指标:
| 指标 | 意义 |
|---|---|
caddy_http_request_duration_seconds |
处理耗时,看 p99 |
caddy_http_response_duration_seconds |
响应体传输耗时 |
caddy_http_requests_in_flight |
在途请求数 |
go_goroutines |
goroutine 数量 |
process_resident_memory_bytes |
常驻内存 |
优化之前先有基线。没数据就动手改,等于闭眼调参。
超时设置
章节「超时设置」{ servers { timeouts { read_body 30s read_header 10s idle 5m write 0 } max_header_size 16KB }}
example.com { reverse_proxy localhost:3000}| 超时 | 默认 | 建议 |
|---|---|---|
read_header |
10s | 保持默认 |
read_body |
无 | 显式设上限,防慢速攻击 |
idle |
5m | WebSocket 应用调大 |
write |
无 | 流式响应设 0(不限制) |
HTTP/2 和 HTTP/3
章节「HTTP/2 和 HTTP/3」{ servers { protocols h1 h2 h3 }}example.com { reverse_proxy localhost:3000}HTTP/3 走 UDP 443。要求:
- 防火墙放通 UDP 443(很多云安全组默认只放 TCP)
- 客户端和服务端之间没有破坏 UDP 的中间设备
- 不支持时会自动回退到 HTTP/2,不会坏
放通 UDP 443 后可用 HTTP/3 测试服务 验证。
WebSocket 转 HTTP/2?
章节「WebSocket 转 HTTP/2?」理论上 WebSocket over HTTP/2 更省连接,但浏览器兼容性还不够稳。Caddy 默认让WebSocket 走 HTTP/1.1 是有道理的,别为了「优化」去动它。
静态文件与 sendfile
章节「静态文件与 sendfile」Caddy 静态文件服务默认用 sendfile 系统调用,零拷贝。这类优化基本不用手动做。
能做的:
example.com { root * /var/www/html encode gzip zstd file_server { precompressed br gzip }}precompressed 让Caddy 直接发你预压缩好的 .br / .gz 文件。构建时生成这些文件,能省掉每次请求的实时压缩 CPU。
构建时裁剪模块
章节「构建时裁剪模块」xcaddy build --with github.com/caddy-dns/cloudflare --with github.com/mholt/caddy-ratelimitcaddy list-modules 看当前有多少个模块,删掉用不到的能减小二进制、减少启动时间和内存占用。
但别裁过头——很多「当前没用」的模块你会在某个深夜需要它,而重新编译比现成可用麻烦得多。
限流
章节「限流」反代前面被刷是常态:
{ order rate_limit before basic_auth}
example.com { rate_limit { zone api { key {http.request.remote.ip} events 100 window 1m } }}需要 mholt/caddy-ratelimit 模块:
xcaddy build --with github.com/mholt/caddy-ratelimit连接数限制
章节「连接数限制」example.com { @tooMany { not remote_ip 192.168.0.0/16 expression ... } respond @tooMany "Too many connections" 429}更实际的做法是用系统工具(nginx 那套 limit_req 逻辑)在更前面挡,比如 Cloudflare 或云厂商的 WAF。
连接复用
章节「连接复用」reverse_proxy localhost:3000 { transport http { keepalive 30s keepalive_idle_conns 32 }}上游连接池。机器上有很多反代目标时,调大 keepalive_idle_conns 能减少握手开销。
内存
章节「内存」- 大文件上传会占用内存做缓冲,
request_body限小能显著降低峰值。 - 日志级别调高会增加内存和磁盘 IO,生产别开
DEBUG。 max_header_size别设太大,每个请求都要预留这个量级的 buffer。
调优 checklist
章节「调优 checklist」# 1. 先确认瓶颈在Caddy 还是上游curl -w "connect: %{time_connect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" \ -o /dev/null -s https://example.com
# 2. 确认 ttfb 大 => 上游慢,Caddy 无能为力# 确认 ttfb 小但 total 大 => 传输慢,查带宽/响应体大小