4. 代理与网关:反向代理、正向代理、Nginx、HAProxy 配置不当导致的错误
说到「Remote end closed connection without response」这个错误,代理和网关绝对是重灾区。我这些年排查过的案例里,至少有一半跟它们有关。你想想看,代理层就像个中间人,它要是脾气不好或者理解错了,直接把后端连接掐了,前端收到的就是这句冷冰冰的提示。
4.1 反向代理 vs 正向代理:谁更容易出问题?
先理清概念。反向代理是替后端服务器挡在前面的,客户端不知道后端是谁。正向代理是替客户端出去访问的,服务器不知道客户端是谁。嗯,这两种场景下,连接被关闭的原因其实不太一样。
| 代理类型 | 典型场景 | 常见错误原因 |
|---|---|---|
| 反向代理 | Nginx 代理后端 API | 后端超时、缓冲区溢出、upstream 配置错误 |
| 正向代理 | 公司内网通过 Squid 访问外网 | 连接池耗尽、SSL 握手失败、ACL 限制 |
我个人习惯把反向代理的问题分成两类:一类是代理主动关闭连接,另一类是代理被动收到了后端的关闭信号然后转发给客户端。前者往往是配置问题,后者往往是后端服务本身扛不住了。
4.2 Nginx 配置不当:最常见的坑
Nginx 是我用得最多的反向代理,也是踩坑最多的。说白了,Nginx 默认配置是给静态网站用的,拿来代理 API 服务,不改几个参数肯定要出问题。
4.2.1 proxy_read_timeout 太短
这个参数控制 Nginx 等待后端响应的最长时间。默认是 60 秒。如果你的后端接口需要处理大量数据,或者有长轮询逻辑,60 秒根本不够用。
解决方案很简单,根据业务场景调整:
# 针对 API 接口,建议设置 120 秒以上
location /api/ {
proxy_pass http://backend;
proxy_read_timeout 120s;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
}
# 针对流式接口或长轮询,可以设置更大
location /stream/ {
proxy_pass http://stream_backend;
proxy_read_timeout 300s;
proxy_buffering off; # 流式接口建议关掉缓冲
}
4.2.2 proxy_buffer 配置不当
Nginx 默认会缓冲后端响应,等攒够了再发给客户端。如果后端返回的数据量很大,而缓冲区太小,Nginx 可能会写磁盘,或者直接报错断开连接。
我记得有一次,后端返回了一个 10MB 的 JSON 数据,Nginx 默认的 proxy_buffer_size 只有 4KB,proxy_buffers 也只有 8 个 4KB 的块。结果 Nginx 一边缓冲一边往磁盘写,最后超时了,连接被关闭。
# 增大缓冲区,避免磁盘 I/O
location /api/ {
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 16 8k;
proxy_busy_buffers_size 16k;
proxy_temp_path /tmp/nginx_proxy_temp 1 2;
proxy_max_temp_file_size 1024m;
}
4.2.3 upstream 配置错误
upstream 块里的配置也经常出问题。比如 max_fails 和 fail_timeout 设置得太激进,导致健康的后端被误判为不可用。
upstream backend {
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
# 如果后端重启频繁,可以调大 fail_timeout
# server 192.168.1.12:8080 max_fails=5 fail_timeout=60s;
keepalive 32; # 启用长连接,减少握手开销
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
这里有个细节:如果 upstream 里启用了 keepalive,但后端不支持 HTTP/1.1 长连接,Nginx 可能会收到后端的 RST 包,然后断开连接。嗯,这个坑我踩过两次才记住。
4.3 HAProxy 配置不当:容易被忽略的细节
HAProxy 比 Nginx 更专注于四层和七层负载均衡,但配置不当同样会导致连接被关闭。
4.3.1 timeout 参数设置
HAProxy 的 timeout 参数非常多,而且每个都有不同的作用域。我见过最典型的问题是 timeout server 设置得太小,导致后端还在处理请求,HAProxy 就把连接关了。
# HAProxy 配置示例
defaults
mode http
timeout connect 5s
timeout client 30s
timeout server 30s # 这个值要跟后端接口耗时匹配
timeout queue 10s
timeout http-request 10s
timeout http-keep-alive 60s
backend api_servers
balance roundrobin
server api1 192.168.1.10:8080 check inter 3s fall 3 rise 2
server api2 192.168.1.11:8080 check inter 3s fall 3 rise 2
4.3.2 连接队列溢出
HAProxy 默认的连接队列大小是 1024。如果并发请求量很大,队列满了之后,新的连接会被直接拒绝,客户端就会收到连接被关闭的错误。
# 增大连接队列
global
maxconn 10000
tune.maxaccept 100
defaults
maxconn 5000
backlog 4096 # 增大 backlog,应对突发流量
我个人习惯在生产环境把 maxconn 设到硬件能承受的上限,同时配合监控告警。一旦连接数接近上限,就要考虑扩容了。
4.4 代理层连接关闭的排查思路
遇到 "Remote end closed connection without response" 时,如果怀疑是代理层的问题,我一般按这个顺序排查:
- 看代理日志:Nginx 的 error.log、HAProxy 的日志,都会记录连接关闭的原因。比如 Nginx 会写 "upstream prematurely closed connection"。
- 检查超时配置:把所有 timeout 参数列出来,跟后端接口的实际耗时对比。
- 检查缓冲区配置:特别是 Nginx 的 proxy_buffers,看是不是太小导致写磁盘了。
- 检查后端健康检查:有时候代理层把后端标记为 down 了,但实际后端是正常的。调整 max_fails 和 check 参数。
- 抓包确认:在代理服务器上用 tcpdump 抓包,看是谁先发的 FIN 或 RST。这个最直接,谁先动手谁有问题。
4.5 知识体系:代理与网关错误的核心逻辑
下面这张图是我自己总结的,代理层连接关闭的几种典型路径。你可以对照着排查问题。
这张图把代理层连接关闭的三种路径都画出来了。实际排查时,先确定是哪种路径,再针对性地检查配置。路径 1 和路径 2 的解决方案完全不同,别搞混了。
好了,代理和网关这块的内容就这些。记住一句话:代理层配置的核心是「匹配」,匹配后端的能力、匹配业务的耗时、匹配网络的状况。配错了,连接就会被关闭。