当使用nginx代理多个网关实例时,

当被请求服务的get 接口异常时,如 error timeout invalid_header http_500 http_502 http_503 http_504,

nginx 会响应 502状态码,

在我之前的认知里,nginx 只会转发 后端服务的响应,一般不会对状态码进行修改

nginx 配置如下:

worker_processes  1;
daemon off;
master_process off;
error_log logs/error.log debug;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format apm '[$time_local]\tclient=$remote_addr\t'
'upstream_addr=$upstream_addr\t'
'upstream_status=$upstream_status\t'
'document_root="$document_root"\t'
'fastcgi_script_name="$fastcgi_script_name"\t'
'request_filename="$request_filename"\t'
'request_time=$request_time\t'
'upstream_response_time=$upstream_response_time\t'
'upstream_connect_time=$upstream_connect_time\t'
'upstream_header_time=$upstream_header_time\t';
access_log logs/access.log apm;
sendfile on;
keepalive_timeout 65;
upstream gateway {
server 192.168.2.102:12012;
server 192.168.2.102:12011;
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location /api/ {
proxy_pass http://gateway/;
proxy_next_upstream error http_503 http_502;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

示例测试代码:

    @GetMapping("/excep503")
public ResponseEntity<String> excep503(HttpServletRequest request, Integer times) throws InterruptedException {
Thread.sleep(200);
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body("服务不可用");
}

测试方法:

多次 get 请求一个异常接口

现象:

有时报错 502 ,有时报错 503



返回 503时

access_log 中的 upstream_addr 会有两条: 192.168.2.102:12012, 192.168.2.102:12011

error_log 会出现分别请求 两台网关的日志:

首先请求 connect to 192.168.2.102:12011 ;

102:12011 返回 503 Service Unavailable

报错

upstream server temporarily disabled while reading response header from upstream

然后 重新指向 connect to 192.168.2.102:12012

102:12012 同样 返回 503 Service Unavailable

返回 502时

access_log 中的 upstream_addr 只会有一条:upstream_addr=192.168.2.102:12011

error_log 只会出现一次请求网关的日志:

请求 connect to 192.168.2.102:12011 ;

102:12011 返回 503 Service Unavailable

报错

upstream server temporarily disabled while reading response header from upstream,
no live upstreams while connecting to upstream,

返回502的原因

根据 查阅相关资料

传入的ft_type为 40000000 匹配到 default ,所以最终状态码为 NGX_HTTP_BAD_GATEWAY ,即 502

nginx-1.24.0\src\http\ngx_http_upstream.c(ngx_http_upstream_next) 4370行;

switch (ft_type) {

    case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
case NGX_HTTP_UPSTREAM_FT_HTTP_504:
status = NGX_HTTP_GATEWAY_TIME_OUT;
break; case NGX_HTTP_UPSTREAM_FT_HTTP_500:
status = NGX_HTTP_INTERNAL_SERVER_ERROR;
break; case NGX_HTTP_UPSTREAM_FT_HTTP_503:
status = NGX_HTTP_SERVICE_UNAVAILABLE;
break; /*
* NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
* never reach here
*/ default:
status = NGX_HTTP_BAD_GATEWAY;
}

502 与 503 的 逻辑分岔路:

nginx-1.24.0\src\http\ngx_http_upstream_round_robin.c(ngx_http_upstream_get_round_robin_peer)449 行

peers = rrp->peers;
ngx_http_upstream_rr_peers_wlock(peers); if (peers->single) {
peer = peers->peer; if (peer->down) {
goto failed;
} if (peer->max_conns && peer->conns >= peer->max_conns) {
goto failed;
} rrp->current = peer; } else { peer = ngx_http_upstream_get_peer(rrp); if (peer == NULL) {
goto failed;
} ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"get rr peer, current: %p %i",
peer, peer->current_weight);
}

其中的 single 标志位是一个用于标识后端服务器组是否只有一个成员的标志,即 upstream_addr 为单个

所以现在的问题是:

为什么 有时upstream_addr是两个 ,有时是一个

debug nginx 源码

nginx启动时 给每个后端节点赋值了一个默认的超时时间 10s

发生异常时将节点标记为不可用:

nginx-1.24.0/src/http/ngx_http_upstream_round_robin.c(ngx_http_upstream_get_peer) 522 行

    for (peer = rrp->peers->peer, i = 0;
peer;
peer = peer->next, i++)
{
n = i / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); if (rrp->tried[n] & m) {
continue;
} if (peer->down) {
continue;
} if (peer->max_fails
&& peer->fails >= peer->max_fails
&& now - peer->checked <= peer->fail_timeout)
{
continue;
} if (peer->max_conns && peer->conns >= peer->max_conns) {
continue;
} peer->current_weight += peer->effective_weight;
total += peer->effective_weight; if (peer->effective_weight < peer->weight) {
peer->effective_weight++;
} if (best == NULL || peer->current_weight > best->current_weight) {
best = peer;
p = i;
}
}

验证

不断请求接口,发现每过10秒,就会恢复503 错误,符合猜测



nginx 配置 proxy_next_upstream 会出现未预期 502 错误问题排查的更多相关文章

  1. nginx 配置虚拟主机访问PHP文件 502错误的解决方法

    最近配置Nginx 服务器虚拟主机 访问目录发现报502错误 百度了很多方法 都不管用  我擦 各种抓狂----- 原本Nginx配置如下: 网上找了很多方法: 查看日志   借助nginx的错误日志 ...

  2. Nginx配置,413 Request Entity Too Large错误解决

    今天有同事找我,说图片上传之后,不知道去哪里了.分析了一下问题,找到原因之后做了处理,这里简要记录一下. 问题原因: 1.首先后台log并无错误信息: 2.捡查了一下浏览器,发现network中有报错 ...

  3. 在阿里云 Ubuntu上通过nginx+uwsgi服务器部署Django出现的502错误

    https://blog.csdn.net/luojie140/article/details/76919471 https://blog.csdn.net/sinat_21302587/articl ...

  4. Nginx 502错误触发条件与解决办法汇总(转载)

    一些运行在Nginx上的网站有时候会出现“502 Bad Gateway”错误,有些时候甚至频繁的出现.有些站长是在刚刚转移到Nginx之后就出现了这个问题,所以经常会怀疑这是不是Nginx的问题,但 ...

  5. nginx 502错误

    一些运行在Nginx上的网站有时候会出现“502 Bad Gateway”错误,有些时候甚至频繁的出现.以下是小编搜集整理的一些Nginx 502错误的排查方法,供参考: Nginx 502错误的原因 ...

  6. nginx中的502错误

    遇到这种情况,首先看一下慢日志 [17-Aug-2015 13:13:43] WARNING: [pool www] child 27780, script '/data/s.com/index.ph ...

  7. Laradock + tp5 + nginx 配置虚拟机域名始终跳转首页/502报错

    laradock默认配置文件如下: 配置运用于本地windows+phpstudy 部署的laravel项目未出现问题,如下: server { listen ; listen [::]:; serv ...

  8. Nginx配置SSL证书实现https访问「浏览器未认证」

    http 和 https 介绍 http:应用最广泛的一种网络协议,是一个B/S的request和response的标准,用于从www服务器传输超文本到本地浏览器的传输协议. https:以安全为目标 ...

  9. nginx配置优化+负载均衡+动静分离详解

    nginx配置如下: #指定nginx进程运行用户以及用户组user www www;#nginx要开启的进程数为8worker_processes 8;#全局错误日志文件#debug输出日志最为详细 ...

  10. 你需要知道的Nginx配置二三事

    做服务端开发的,工作中难免会遇到处理Nginx配置相关问题.在配置Nginx时,我一直本着“照葫芦画瓢”的原则,复制已有的配置代码,自己修修改改然后完成配置需求,当有人问起Nginx相关问题时,其实仍 ...

随机推荐

  1. 交换机:ToR、EoR

    参考链接: 交换机:ToR.EoR ToR:(Top of Rack)接入方式就是在服务器机柜的最上面安装接入交换机. EoR:(End of Row)接入交换机集中安装在一列机柜端部的机柜内,通过水 ...

  2. 代码随想录算法训练营第三天| LeetCode 203.移除链表元素(同时也对整个单链表进行增删改查操作) 707.设计链表 206.反转链表

    203.移除链表元素         题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1 ...

  3. 规范代码编写风格就用 eslint 和 prettier

    eslint 可以用于规范我们的编码,使得项目中的代码风格一致,更利于阅读和维护,而 prettier 可以在当我们代码不符合 eslint 规范是进行部分自动修复. eslint 通过 npm in ...

  4. 如何将 dubbo filter 拦截器原理运用到日志拦截器中?

    业务背景 我们希望可以在使用日志拦截器时,定义属于自己的拦截器方法. 实现的方式有很多种,我们分别来看一下. 拓展阅读 java 注解结合 spring aop 实现自动输出日志 java 注解结合 ...

  5. go创建web项目分别在windows和linux部署

    转载请注明出处: 要在Linux服务器上运行Go的Web项目,可以按照以下步骤进行操作: 在服务器上安装Go:首先,在Linux服务器上安装Go编程语言.你可以从官方网站(https://golang ...

  6. cs50ai1

    cs50ai1-------Knowledge cs50ai1-------Knowledge 基础知识 课后题目 代码实践 学习链接 总结 基础知识 对我们来说,一些基本的logic是自然而然的,我 ...

  7. 《Web安全基础》02. 信息收集

    @ 目录 1:CDN 绕过 1.1:判断是否有 CDN 服务 1.2:常见绕过方法 1.3:相关资源 2:网站架构 3:WAF 4:APP 及其他资产 5:资产监控 本系列侧重方法论,各工具只是实现目 ...

  8. [Bread.Mvc] 开源一款自用 MVC 框架,支持 Native AOT

    Bread.Mvc Bread.Mvc 是一款完全支持 Native AOT 的 MVC 框架,搭配同样支持 AOT 的 Avalonia,让你的开发事半功倍.项目开源在 Gitee,欢迎 Star. ...

  9. 纯前端导出word手写复杂表格,并还原成word。百分百还原表格。一文搞定前端表格导出为word

    本次的需求是手写一个养老院老人生活能力评定表,并且要能够录入信息,最终导出 表格因为有七页所以代码很多,可以不用看表格模板的详细代码. 先贴上最终效果图 填写完导出之后 基本上实现了样式的百分百还原导 ...

  10. QA|外部调用类方法总报错missing 1 required positional argument:'self'|UI自动化

    外部调用类方法总报错missing 1 required positional argument:'self' 原因:实例化这个类 实例化错了,少了括号() 解决:改成如下就可以了 参考学习:调用类方 ...