kubernetes ingress-nginx 启用 upstream 长连接,需要注意,否则容易 502

本篇目录

说明

之前踩过这个坑,在《使用 nginx 作反向代理,启用 keepalive 时,遇到 502 错误的调查过程》 中了记录调查过程,当时多个案例同时查,记录的比较乱,这里重新整理一下结论。

ingress-nginx 到 upstream 的长连接通过 configmap 中的 upstream-keepalive-connections 等参数设置,注意与 keep-alive 区分(见文末)。另外 ingress-nginx 0.20 之前的版本有 bug,即使配置了也不生效:ingress-nginx upstream 的 keep-alive 不生效

三个结论

这里主要解释结论 3,这里的结论不仅适用于 ingress-nginx,也适用于其它使用 nginx 的场景。

结论1:nginx 的端口耗尽时,会返回 502 错误(和本文要讨论的内容无关)。

结论2:nginx 向已经被服务端主动断开的连接发送请求,会收到 RST,然后返回 502。

结论3:服务端先于 nginx 断开连接的情况有两种,

1)服务端的连接超时时间小于 nginx 中的配置;

2)服务端配置的单个连接的最大请求数小于 nginx 中配置。

为什么服务端有超时时间和最大请求数限制?

服务端应用可能是通过本地的 tomcat 或者其它 web 框架对外暴露的,这种情况非常普遍。 这些 Web 服务或者框架通常都有默认的长连接设置。

譬如 tomcat 的 相关配置

tomcat 的 maxKeepAliveRequests

tomcat 的 connectionTimeout

tomcat 的 keepAliveTimeout

另外曾经遇到过的 Gunicorn 超时时间只有 2 秒:

Gunicorn 的超时时间设置

nginx 的配置与后端服务的配置不一致时

如果做反向代理的 nginx 中配置的连接断开条件比后端服务设置的条件宽松,那么就容易出现后端服务先断开连接的情况, 这时候 nginx 转发请求到 upstream,upstream 会返回 RST,nginx 打印下面的错误日志,给客户端返回 502:

2019/06/13 04:57:54 [error] 3429#3429: *21983075 upstream prematurely closed connection while reading 
response header from upstream, client: 10.19.167.120, server: XXXX.com, request: "POST XXXX HTTP/1.0",
upstream: "http://11.0.29.4:8080/XXXXXX", host: "XXXX.com"

2019/06/13 04:58:34 [error] 3063#3063: *21989359 recv() failed (104: Connection reset by peer) while 
reading response header from upstream, client: 10.19.138.139, server: XXXX.com, request: 
"POST /api/v1/XXXX HTTP/1.1", upstream: "http://11.0.145.9:8080/api/v1/XXXX", host: "XXXX.com"

建议设置

可以调整 nginx 的 upstream 中 keepalive_timeoutkeepalive_requests,确保 nginx 先于 upstream 断开连接。只有 nginx 与 upstream 之间使用长连接的时候需要考虑这种情况,并进行类似的设置。

upstream record_upstream {
    server  127.0.0.1:9091;
    keepalive 16;
    keepalive_timeout  58s;    # 默认 60 s,根据实际情况调整,建议小于 60s
    keepalive_requests 98;     # 默认 100 个,根据实际情况调整,建议小于 100
}

server {
    ...
    location /http/ {
        proxy_pass http://record_upstream;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        ...
    }
}

nginx 的 keepalive_timeout 和 keepalive_requests 参数各有两个:一组属于 ngx_http_core_module,在 http/server/location 中使用,限制的是 client 与 nginx 之间的连接;另一组是上面使用的,属于 ngx_http_upstream_module,限制的是 nginx 与 upstream 之间的连接。

默认行为

nginx 的 upstream 中没有明确配置 keepalive,那么无论 client 和 nginx 之间是否长连接,nginx 和 upstream 都是短连接。

用下面的配置观察:

upstream record_upstream {
    server  127.0.0.1:9091;

    #keepalive 3;
    #keepalive_timeout  58s;
    #keepalive_requests 98;
}

server {
    listen       9000;
    listen       [::]:9000;
    server_name  echo.example;
    keepalive_requests  2000;
    keepalive_timeout 60s;

    location / {
        proxy_pass  http://record_upstream;
        #proxy_http_version 1.1;
        #proxy_set_header Connection "";
    }
}

使用长连接访问 nginx :

wrk -c 1 -t 1 -d 2s  http://127.0.0.1:9000

http-record 收到的请求是 “Connection: close”:

/go/src/Server/echo.go:46: {
    "RemoteAddr": "172.17.0.1:34522",
    "Method": "GET",
    "Host": "record_upstream",
    "RequestURI": "/",
    "Header": {
        "Connection": [
            "close"
        ]
    },
    "Body": ""
}

参考

  1. 李佶澳的博客
  2. 使用Nginx作反向代理,启用keepalive时,遇到502错误的调查过程

推荐阅读

赞助商广告

Copyright @2011-2019 All rights reserved. 转载请添加原文连接,合作请加微信lijiaocn或者发送邮件: [email protected],备注网站合作

友情链接:  李佶澳的博客  小鸟笔记  软件手册  编程手册  运营手册  爱马影视  网络课程  奇技淫巧  课程文档  精选文章  发现知识星球  百度搜索 谷歌搜索