一、nginx故障转移
我们都知道nginx可以用作负载均衡可以通过轮训、weight、ip_hash、url_hash、fair的方式很好的分散请求的压力。基于nginx阿里也有自己的tengin。
同时Nginx可以对故障转移进行配置,相关的配置项如下所示:
server
{
listen 80;
server_name www.yourdomain.com 192.168.203.42;
index index.html index.htm;
root /data/htdocs/www;
location /
{
#故障转移的条件:如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_send_timeout 10s; # 代理发送超时时间
proxy_read_timeout 10s; # 代理接收超时时间
proxy_next_upstream_tries 3; # 重试次数
proxy_cache cache_one;
#对不同的HTTP状态码设置不同的缓存时间
proxy_cache_valid 200 304 12h;
#以域名、URI、参数组合成Web缓存的Key值,Nginx根据Key值哈希,存储缓存内容到二级缓存目录内
proxy_cache_key $host$uri$is_args$args;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://backend_server;
expires 1d;
}
}
如配置webserver1、webserver2、webserver3 三台集群,当有请求过来时会根据配置的负载均衡策略进行请求转发。如请求A被转发到webserver1中,但因为webserver服务器压力过大,产生了proxy_next_upstream中配置的现象,如超时未返回数据等现象,便会出发nginx的故障转移机制,将请求转发到其余服务器上进行处理。
好处: 保证了集群的高可用
坏处: 频繁的进行请求转发会给集群带来压力,甚至造成雪崩。
二、事件
2.1 问题描述:
有一个发送短信的http服务,客户端调用之后,只有一次请求,但是发了三次短信。
分析:
1、客户端仅发起了一次请求,
2、服务端收到了三次请求
3、三次请求分别落在了三台后端机器上。每台后端机器仅收到一次请求
2.2 基本的架构:
2.3 分析及解决:
分析代码,代码中没有重试机制,并且通过请求分布来看,并不是一台机器处理了三次,而是每台机器处理了一次。所以分析,可能是由于nginx转发导致。
查看接口的响应时间,发现每个接口的响应时间为18s左右(PS:由于是调用外部接口,此调用时间属于正常的时间。。。)。
猜测是由于后端服务器未能及时返回数据,导致了nginx的超时重试机器,将请求分发到了另外一台机器上。
查看nginx的配置文件,发现如下配置:
proxy_next_upstream http_502 http_504 error timeout invalid_header;
上面的配置表示,如果后端服务器如下情况,将会把请求转发到下一台后端服务器上。
error - 在连接到一个服务器,发送一个请求,或者读取应答时发生错误。
timeout - 在连接到服务器,转发请求或者读取应答时发生超时。
invalid_header - 服务器返回空的或者错误的应答。
http_502 - 服务器返回502代码。
http_504 - 服务器返回504代码。
继续查看超时时间
proxy_read_timeout 15;
超时时间为15s,所以后端服务器响应慢,nginx没有在15s内收到返回的数据,所以将请求切换到下一台后端机器了,所以,同样的情况下, 请求第二台后端机器时,也没有在规定的时间内得到响应,所以又切换到第三台机器了,最终导致短信发送了三次。
几个参数说明:
proxy_send_timeout 后端服务器数据回传时间(代理发送超时时间)
proxy_read_timeout 连接成功后,后端服务器响应时间(代理接收超时时间)
proxy_connect_timeout nginx连接后端的超时时间,一般不超过75s
如何解决呢?
第一种办法:因为后端机器无法再进行优化减少响应时间,所以可以更改nginx的超时时间,将原本的15s更改为40s,这样可以保证结果正常返回。
第二种办法 :关闭自动切换到下台机器的功能,即将proxy_next_upstream配置为off。但是这样虽然能解决问题,但是会导致nginx的容错能力下降。
第三种,最后的才是最香的:
nginx的熔断机制:
当某台被代理服务器处理请求,出现一定次数的错误的情况下,nginx在一定时间内不再将请求分配给这台服务器进行处理。 过了熔断时间后,nginx会再次尝试分配一次请求给该服务器处理,如果还是失败,那么继续熔断。
upstream指令块中server定义的熔断参数配置:
max_fails = number; # 熔断机制的错误次数 阈值(默认1)
fail_timeout = time #熔断时间(nginx标记服务器不可用的持续时间,默认10s)
示例: server 192.168.1.100 max_fails=3 fail_timeout= 10s;
以上现象还可能出现在以下的场景:
1、上传excel,然后服务端处理excel内容,插入到db里面的时候,可能存在多次转发导致数据重复。
2、post请求处理时间过长,可能出现重复提交的问题。