首页 > 经验记录 > Nginx的容灾其实还是不大靠谱

Nginx的容灾其实还是不大靠谱

Nginx 自带了流量切换机制,只需要在 upstream 里配置就能实现轮询或者权重切流,比如下面这样:

upstream gateway_backend {
    server 192.168.0.135:8800;
    server 192.168.0.136:8800;
    server 192.168.0.137:8800;
}

但他自带的容灾机制,却并不靠谱,Nginx 并不会自动检测后端服务器是否存活

他只能设置【如果请求 x 次失败】则【接下来的 y 秒内不再请求这个节点】 ,是一个被动的检查

upstream gateway_backend {
    # 下面的配置用 fail_timeout 和 max_fails,属于简易健康检查
    # 意思是失败3次,就5秒内不再请求这台
    server 192.168.0.135:8800 max_fails=3 fail_timeout=5s;
    server 192.168.0.136:8800 max_fails=3 fail_timeout=5s;
    server 192.168.0.137:8800 max_fails=3 fail_timeout=5s;
}

而这个“失败”的定义,也是取决于 Nginx 本身自带的设定,即它无法知道你的服务到底怎么样了,所以他就必须要去试着请求。

这意味着哪怕配置了轮询,但其中一台服务(比如 192.168.0.136)挂了,Nginx 还是会继续把流量转发给它。

用户访问到这台挂掉的机器时会报错(如 502 Bad Gateway),因此会影响访问流量。按上面写的 max_fails=3 的配置来说,就是说起码出现 3 个请求的响应失败,才会下线节点。

 

 

而这个检测到失败又分为不同的情况。

如果机器还在,端口关闭(常见的 kill 掉应用进程),Nginx 尝试连接时会直接收到 TCP 的 ECONNREFUSED,这会立即返回失败,不需要等proxy_connect_timeout,每一次失败就算一次 max_fails,所以连续访问这个节点三次后,它会被暂时剔除。

这是比较理想的处理路径,failover 很快。

 

但如果是后端服务器完全不可达(如宕机或断网),Nginx 不知道对面什么情况,那他可能就需要等待 proxy_connect_timeout(连接超时)或 proxy_read_timeout(读取超时)才会判定一次请求失败。

比如我们的设置为:

# http_proxy 设置
client_body_buffer_size   128k;
proxy_connect_timeout   75;
proxy_send_timeout   75;
proxy_read_timeout   75;
proxy_buffer_size   4k;
proxy_buffers   4 32k;
proxy_busy_buffers_size   64k;
proxy_temp_file_write_size  64k;

proxy_connect_timeout 为 75,那么当我设置 max_fails=3 时,若某个服务宕机,假设请求连续触发且每次都耗尽 75 秒的 proxy_connect_timeout。

最坏情况可能造成:3 次请求 × 每次最多 75 秒 = 最坏情况约 225 秒(3 分 45 秒)后才会临时剔除该节点。如果请求间隔较长,实际下线时间可能更久。

这是最坏的情况,但,在高延迟或网络不稳定的环境中,确实会出现。

哪怕不出现最坏的情况(毕竟现在基本都是一个内网),按理想情况来看,Nginx还是会把你的用户请求实打实转发给已经挂掉的服务器,直到失败一定次数,这真的能接受吗?

 

如果真的需要秒级容灾 + 零中断转发,那么,放弃Nginx或许是一个好的选项。

单单一个Nginx往前套已经是旧时代的搞法了,大伙都用OpenResty 、Envoy,也是该换换。

           


CAPTCHAis initialing...
EA PLAYER &

历史记录 [ 注意:部分数据仅限于当前浏览器 ]清空

      00:00/00:00