V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kisshere
V2EX  ›  程序员

nginx 反代高并发时,偶尔出现 upstream timed out 该怎么排查原因?

  •  
  •   kisshere · 70 天前 · 2767 次点击
    这是一个创建于 70 天前的主题,其中的信息可能已经有所发展或是发生改变。

    高并发状态下,error_log 偶尔出现:

    upstream timed out (110: Connection timed out) while reading response header from upstream
    

    因为是偶尔出现这个 time out, 我自己访问又没有任何问题,所以不知道该怎么排查,是 upstream 服务器请求太多处理不过来?还是反代服务器和 upstream 服务器网络连接有问题,还是反代服务器 nginx 配置问题?

    so 上给出的最高赞答案: https://stackoverflow.com/questions/18740635/nginx-upstream-timed-out-110-connection-timed-out-while-reading-response-hea 把 proxy_read_timeout 加大就可以了,感觉完全是治标不治本啊

    nginx 能不能设置一个超过 time out 就自动再向 upstream 服务器重新发送请求的功能?

    29 条回复    2022-10-08 11:45:38 +08:00
    seers
        1
    seers  
       70 天前
    proxy_next_upstream 配置看看
    justest123
        2
    justest123  
       70 天前   ❤️ 1
    以前学 Nginx 的时候收藏的一篇博客[TCP SOCKET 中 backlog 参数的用途是什么?]( https://www.cnxct.com/something-about-phpfpm-s-backlog/),其中提到过上游服务 backlog 过大的情况下,可能来不及处理,导致 Nginx 超时报 110 (提一个思路,不一定是这个问题
    picone
        3
    picone  
       70 天前   ❤️ 9
    首先要理解这个错误,请求分 3 个阶段,连接,写,读,这个错误意思是读的时候超时了。那错误本身就是从 upstream 读取请求结果超时。我认为的排查方向:
    - 找到下游服务对应的日志,看看请求处理时间是多少。经验来说这个问题可能性最大,需要下游增加处理请求超时。
    - 网络问题,下游返回回包了,上游没接到,看一下网络 IO 是不是打满了,看一下 TCP 重传的指标。
    - 超时重试有 proxy_next_upstream ,但是注意幂等请求。https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
    qoo2019
        4
    qoo2019  
       70 天前
    proxy_next_upstream error timeout http_500;
    julyclyde
        5
    julyclyde  
       70 天前
    应该是上游处理能力满了
    nginx 到上游的连接,在上游的处理能力以外,但还在 backlog 范围内
    上游内核会先接受 tcp 连接,等实际服务的程序调用 accept 获得这个链接
    redford42
        6
    redford42  
       70 天前
    可以看一下服务器的 tcp 链接是否有丢弃请求的情况
    zliea
        7
    zliea  
       70 天前
    upstream 用 keepalive 了么?
    zliea
        8
    zliea  
       70 天前
    还需要看是否需要调整后端服务器的连接数。
    facelezz
        9
    facelezz  
       70 天前
    @picone 是的 既然都是 reading timeout 那出错的方向 肯定在 nginx 和你的服务上 1.检查 I/O 2.带宽 3.检测丢包情况 4.你的服务偶尔超时 5.proxy_read_timeout 过小(严格上来讲还是属于 4 ) 楼上提到的 proxy_next_upstream 可以让 ng 在这个情况下 重试下一个 upstream 里的节点

    经验来说 4 可能性最大,连接数我觉得不需要调整,毕竟是 reading timeout (已经连上了)
    facelezz
        10
    facelezz  
       70 天前
    不过 4 的话 你们有 APM 的话 应该很容易发现吧
    lambdaq
        11
    lambdaq  
       70 天前
    二楼 @justest123 的回答是对的。就是你代码处理不过来排队了,后面的请求一看卧槽排这么长的队就 gg 了。
    lambdaq
        12
    lambdaq  
       70 天前
    有一个思路是 nginx 请求的时候带上一个头比如 proxy_set_header x-nginx-time $time_iso8601;

    然后你在代码接到请求里对比一下,看下别人请求在排队的时候蹲了多长时间。
    facelezz
        13
    facelezz  
       70 天前   ❤️ 1
    @lambdaq 那也不对吧 backlog 过大是 Connection timed out 过小是 Connection refused 题主的报错不是 reading timeout 么
    julyclyde
        14
    julyclyde  
       70 天前
    @facelezz backlog 过大的话是可以建立连接的
    建立连接和 backlog 是内核处理的。user space 的是 accept 从已经建立的连接们取一个回来
    kisshere
        15
    kisshere  
    OP
       69 天前 via Android
    @facelezz 那请问一下,怎么查看当前 Nginx 默认的 proxy_read_timeout 呢?谢谢
    lambdaq
        16
    lambdaq  
       69 天前
    @facelezz backlog 过大,已经连上的比如有 1000 个,但是都过了 60s 没能得到 accept(),那么 nginx 还是会 upstream timed out 的。

    upstream 其实很多时候压根不知道 nginx 已经放弃请求了,还在那里吭哧吭哧挨个处理队列呢。。。
    facelezz
        17
    facelezz  
       69 天前
    @julyclyde
    @lambdaq
    这就超出我知道的知识了,只是感觉 reading timeout 看上去不像是这个问题

    @kisshere 默认好像是 60s 可以 Google 下
    julyclyde
        18
    julyclyde  
       69 天前
    @facelezz reading timeout 就是 exactly 这个问题
    如果把 backlog 设小一点,早就失败然后下一个了
    facelezz
        19
    facelezz  
       69 天前
    @julyclyde 这样吗 学到了~
    kisshere
        20
    kisshere  
    OP
       69 天前
    @picone 下游服务对应的 error_log 日志只记录了 host 和 referer 还有请求网址,没有处理时间啊?
    kisshere
        21
    kisshere  
    OP
       69 天前
    @facelezz 查了下默认超时是 60s ,话说你愿意等待一个网页加载超过 60s 么?大多数人等个三四秒没反应就关闭网页了,这个超时时间加长和没加长又有什么区别。。。
    picone
        22
    picone  
       69 天前
    @lambdaq 查了一下 nginx 的 backlog 的配置文档:
    sets the backlog parameter in the listen() call that limits the maximum length for the queue of pending connections. By default, backlog is set to -1 on FreeBSD, DragonFly BSD, and macOS, and to 511 on other platforms.
    这个 backlog 也就是 listen 队列的长度。其实调整这个感觉是治标不治本,相当于更多需要 accept 的连接都没被处理到,如果都 accept 了就是往 upstream 建立更多的连接。upstream 其实是能指定 nginx 放弃请求的,TCP 会 FIN ,对应比如 Go 里面就是 context canceled 。
    定位错误的另外一个方法是开启 debug 级别的日志观察一下。
    picone
        23
    picone  
       69 天前
    @kisshere 下游服务也是 nginx 服务? 可以查一下下游的 access_log ,如果是对应的请求有 499 的话基本实锤是下游服务的问题了。
    感觉你们的日志并没有串起来,建议在最上游的服务搞一个 logid/traceid 之类含义的字段,放 header ,然后全链路都透传这个字段,查日志就能一一对应了。
    lambdaq
        24
    lambdaq  
       69 天前
    @picone 这里说的不是 nginx 的 backlog 。说的是响应 nginx 请求的 upstream 的 backlog 。
    facelezz
        25
    facelezz  
       69 天前
    @kisshere 不是 这个有的公司会配的很短 你如果没配的话 就没必要改
    facelezz
        26
    facelezz  
       69 天前
    我感觉这个少了 APM 和日志链 并不好排查 可以按照上面的提示调整下 backlog 或者配置 proxy_next_upstream 来缓解
    dusu
        27
    dusu  
       69 天前 via iPhone
    1. Accesslog 里把 upstream_response_time 写上
    2. 自己写个 bash 统计上游平均响应时长
    3. ss -s 看看系统连接情况
    4. ss -tlnp 看 backlog 占用情况
    kisshere
        28
    kisshere  
    OP
       69 天前
    @dusu 试了,upstream_response_time 几乎都是在毫秒范围内,出现了极个别“-”值
    julyclyde
        29
    julyclyde  
       62 天前
    你把 upstream server address 记录下来看看,有些请求可能会有好几个 upstream server address
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3473 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 47ms · UTC 04:57 · PVG 12:57 · LAX 20:57 · JFK 23:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.