今天线上系统出了点问题,机房的电信出口突然不通了,原本以为能自动切换的nginx配置,居然没有生效,导致了业务告警,手工紧急处理了才解决了。
当时的设想是,如果这个服务的访问,出现了500或者超时的情况,会自动重试到下一个服务器去,采用的是nginx的proxy_next_upstream, 配置大概如下:
upstream example_upstream{
server 192.168.0.1 max_fails=1 fail_timeout=30s;
server 192.168.0.2 max_fails=1 fail_timeout=30s backup;
}
location /example/ {
proxy_pass http://example_upstream/;
proxy_set_header Host: test.example.com;
proxy_set_head X-real-ip $remote_addr;
proxy_next_upstream error timeout http_500;
}
按照设想,如果192.168.0.1这台服务器返回了超时或者500,那么访问 /example/ 时应该会自动重试到下一台服务器去,即到192.168.0.2去。
但是情况并没有发生,于是造成了业务故障。
事后我使用openresty,写了些简单的hello world来测试nginx的这个proxy_next_upstream, 完全没有问题呀,可是线上的这个服务就是不行,真的想砸了电脑的心都有了。
在公司反反复复试验了几十次,快到晚上十点才下班回家。回家路上突然想到一种可能,兴奋得想赶紧回到家试验试验。然而到家后试验,并未成功,甚是失望。又反反复复试验了一个小时,总是失败。
然后重新看文档,Module ngx_http_proxy_module ,走投无路,只能逐字逐句看文档了,突然看到这么一段:
这段在公司查找的时候就看到了,但是对non-idempotent 这个单词,我不认识,然后想当然的理解为某个意思,于是就没有去认真看完这段话,觉得和问题没有关系。
把这个配置加进去,变成: proxy_next_upstream error timeout http_500 non_idemponent; 问题终于解决了。
这段话的意思是说,像 post, lock, patch 这种会对服务器造成不幂等的方法,默认是不进行重试的,如果一定要进行重试,则要加上这个配置。
至于为什么我用openresty写的试验会成功,而线上的这个服务一直失败的原因,实则是因为我试验的接口是GET访问的,而线上的服务是POST访问的。
之所以今天会出现这个故障,也是因为线上系统最近升级了nginx,如上图所示,这个配置是 1.9.13版本之后才有的。