当使用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. 自学前端-HTML5+CSS-综合案例一-热词

    综合案例一-热词 目录 综合案例一-热词 1.设计需求 2.设计所需标签和CSS样式 3.设计具体步骤 4.遇到的问题 设计图如下 1.设计需求 ①需要鼠标放上去有显示透明 ②需要点击后跳转到相应页面 ...

  2. MyBatis使用注解开发(及Sqlsession连接器的本质)

    使用注解开发 底层实现机制是反射和,动态代码.反射可以获得这个类的方法属性还可以创建对象,执行方法. 面向接口编程 之前学过,面向对象编程,也学习过接口.但是真正的开发中,很多时候我们会选择面向接口编 ...

  3. windows相关DOS命令简介与基操

    作为程序员要求掌握最基本的windows相关的DOS命令(详细版) 一.DOS命令.cmd.windows操作系统中保留的DOS命令分别是什么? 1.DOS命令是什么? DOS命令,计算机术语,是指D ...

  4. C#的重载决策

    重载是许多编程语言支持的特性.所谓重载,就是指可以定义多个名称相同但参数(个数.类型和顺序)不同的方法(函数).先来看一个例子: void Main() { char cvalue = 'a'; ma ...

  5. 7.1 C++ STL 非变易查找算法

    C++ STL 中的非变易算法(Non-modifying Algorithms)是指那些不会修改容器内容的算法,是C++提供的一组模板函数,该系列函数不会修改原序列中的数据,而是对数据进行处理.查找 ...

  6. 详情讲解canvas实现电子签名

    签名的实现功能 我们要实现签名: 1.我们首先要鼠标按下,移动,抬起.经过这三个步骤. 我们可以实现一笔或者连笔. 按下的时候我们需要移动画笔,可以使用 moveTo 来移动画笔. e.pageX,e ...

  7. MATLAB入门小操作(数据类型)

    这是一篇有助于快速上手MATLAB软件的文章(新手向).(学习过其他的语言更容易看懂) 数据类型 这篇文章我想从MATLAB中的数据类型出发去列举一些经常使用的操作.MATLAB中的数据类型包括其他语 ...

  8. CI框架的base_url localhost [::1]等问题

    为什么localhost变成了[::1] [::1]是IP6的地址, 与localhost等价 使用base_url后, 加载不了样式 ci框架需要定义base_url, 未定义就会出现返回local ...

  9. Go运算操作符全解与实战:编写更高效的代码!

    本文全面探讨了Go语言中的各类运算操作符,从基础的数学和位运算到逻辑和特殊运算符.文章旨在深入解析每一种运算操作符的工作原理.应用场景和注意事项,以帮助开发者编写更高效.健壮和可读的Go代码. 简介 ...

  10. 分享一个 SpringBoot + Redis 实现「查找附近的人」的小技巧

    前言 SpringDataRedis提供了十分简单的地理位置定位的功能,今天我就用一小段代码告诉大家如何实现. 正文 1.引入依赖 <dependency> <groupId> ...