nginx - 故障转移

nginx的重试机制就是容错的一种

官方链接:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream

一、proxy_next_upstream 语法

Syntax: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | non_idempotent | off ...;
Default:
proxy_next_upstream error timeout;
Context: http, server, location

error
an error occurred while establishing a connection with the server, passing a request to it, or reading the response header;
timeout
a timeout has occurred while establishing a connection with the server, passing a request to it, or reading the response header;
invalid_header
a server returned an empty or invalid response;
http_500
a server returned a response with the code 500;
http_502
a server returned a response with the code 502;
http_503
a server returned a response with the code 503;
http_504
a server returned a response with the code 504;
http_403
a server returned a response with the code 403;
http_404
a server returned a response with the code 404;
http_429
a server returned a response with the code 429 (1.11.13);
non_idempotent
normally, requests with a non-idempotent method (POST, LOCK, PATCH) are not passed to the next server if a request has been sent to an upstream server (1.9.13); enabling this option explicitly allows retrying such requests;
off
disables passing a request to the next server.

该指令能够生效的前提是我们没有向客户端发送一个字节,即没有向客户端发送任何的内容,只要向客户端发送了一个字节了,说明上游服务已经生效了,那么我们就不能再选择一个新的上游服务了。所以它是在接收到请求并且在转发一个字节之前,nginx判定为错误,那么这个功能才能够生效。

在Nginx配置文件中,proxy_next_upstream用于指定在什么情况下Nginx会将请求转移到其他服务器上。其默认值是proxy_next_upstream error timeout,即发生网络错误以及超时,才会重试其他服务器。默认情况下服务返回500状态码是不会重试的,如果想在响应500状态码时也进行重试,可以配置:

proxy_next_upstream error timeout http_500;

当然还有http_502http_503http_404等可以指定在出现哪些状态码的情况下需要重试,The cases of errortimeout and invalid_header are always considered unsuccessful attempts, even if they are not specified in the directive. The cases of http_500http_502http_503http_504, and http_429 are considered unsuccessful attempts only if they are specified in the directive. The cases of http_403 and http_404 are never considered unsuccessful attempts.

二、测试案例

2.1 上游突然宕机情况

当与上游建立链接后,上游处理过程中突然宕机,则nginx 判断为 error ,会自动转发至下一个上游服务;注意此时并没有返回错误码。

2.2 上游内部错误情况(返回50X错误码)

2.2.1 Get 请求(幂等)

用一个最简单的例子来测试一下该特性,例如下面是Spring Boot写了一个简单的HTTP接口,返回500状态码:

@RequestMapping("/")
public String test() {
    System.out.println("收到一个请求"); // 打印日志
    throw new RuntimeException(); // 抛出异常, 返回500状态码
}

分别使用9030和9031两个端口号启动该Spring Boot服务,然后Nginx配置好负载均衡:

upstream nginxretry {
    server 127.0.0.1:9030 max_fails=0;
    server 127.0.0.1:9031 max_fails=0;
}
server {
    listen 9039;
    location / {
        proxy_pass http://nginxretry;
        proxy_next_upstream error timeout http_500;
    }
}

注意:以上配置中max_fails=0是为了更方便的测试Nginx错误重试机制。max_fails默认值是1,用于指定一个server在一段时间内(默认10s)发生错误次数达到多少次,Nginx就会自动将该服务器下线。这里设置为0是禁用这个特性,防止在测试过程中服务器被踢下线不好测试。线上环境下一般不会设置max_fails=0。

配置完成后重启Nginx,使用GET方式请求 http://localhost:9039/ ,再分别查看9030和9031两个端口号对应的服务日志,可以发现两个服务都收到请求,也就是Nginx在访问其中一个服务收到500错误状态码后,又尝试去访问另一个服务。

2.2.1 Post 请求(非幂等)

再次使用POST方式请求 http://localhost:9039/ ,再分别查看9030和9031两个端口号对应的服务日志,可以发现只有一个服务收到请求。也就是当请求类型是POST时,Nginx默认不会失败重试。如果想让POST请求也会失败重试,可以继续向下阅读。

Nginx文档中可以看到proxy_next_upstream有一个选项  non_idempotent :

通常情况下,如果请求使用非等幂方法(POST、LOCK、PATCH),请求失败后不会再到其他服务器进行重试。加上non_idempotent选项后,即使是非幂等请求类型(例如POST请求),发生错误后也会重试。

如果想让POST请求也会失败重试,需要配置non_idempotent

upstream nginxretry {
    server 127.0.0.1:9030 max_fails=0;
    server 127.0.0.1:9031 max_fails=0;
}
server {
    listen 9039;
    location / {
        proxy_pass http://nginxretry;
        proxy_next_upstream error timeout http_500 non_idempotent;
    }
}

重启Nginx后再次使用POST请求访问 http://localhost:9039/ ,再分别查看9030和9031两个端口号对应的服务日志,可以看到两个服务都收到请求,也就是POST请求也会重试了。不过实际上在生产环境中,不建议加上non_idempotent选项,具体原因可以继续往下阅读。

在做业务开发是如何理解幂等性,举个最简单的例子:GET方法一般用于获取数据,如果获取的是数据库数据,对应的是SELECT语句。同样的SELECT语句执行一次还是多次,都不会影响数据。而POST一般对应INSERT,如果执行多次后,可能会造成数据重复插入的问题。所以不要使用GET方法做一些INSERT操作,在业务开发时要遵循HTTP协议规范。

生产环境中为什么不建议加上non_idempotent选项?因为无论是发生500错误还是timeout,服务器上的业务可能都已经执行过了,而重试会导致非幂等方法重复执行,从而导致业务问题,例如一个请求会创建了多个订单,或者收到多条短信的问题。

参考:

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream

https://blog.csdn.net/xiao__gui/article/details/89441162

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值