Nginx 健康检查和负载均衡机制分析

栏目: 服务器 · Nginx · 发布时间: 7年前

nginx 是优秀的反向代理服务器,这里主要讲它的健康检查和负载均衡机制,以及这种机制带来的问题。所谓健康检查,就是当后端出现问题(具体什么叫出现问题,依赖于具体实现,各个实现定义不一样),不再往这个后端分发请求,并且做后续的检查,直到这个后端恢复正常。所谓负载均衡,就是选择后端的方式,如何(根据后端的能力)将请求均衡的分发到后端。此外,当请求某个后端失败时,要将该请求分发到其它后端(redispatch)。这里以ngx_http_upstream_round_robin(简称RR)做为负载均衡模块,以ngx_http_proxy_module(检查proxy)作为后端代理模块。

nginx 的健康检查和负载均衡是密切相关的,它没有独立的健康检查模块,而是使用业务请求作为健康检查,这省去了独立健康检查线程,这是好处。坏处是,当业务复杂时,可能出现误判,例如后端响应超时,这是可能是后端宕机,也可能是某个业务请求自身出现问题,跟后端无关。如果后端宕机,nginx还要在将它标记为不可用之后,仍不时的将业务请求分发给它,以检查后端是否恢复。

nginx 完成客户端请求Header部分的解析,upstream 调用RR模块的peer.get 选择具体的后端。当请求结束,upstream 调用RR模块的peer.free,向RR反馈后端的健康情况。当upstream和后端通信时,出现错误会调用 ngx_http_upstream_next,

void ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t ft_type); 第三个参数指明错误类型,共有如下错误类型

#define NGX_HTTP_UPSTREAM_FT_ERROR          0x00000002

#define NGX_HTTP_UPSTREAM_FT_TIMEOUT        0x00000004

#define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER  0x00000008

#define NGX_HTTP_UPSTREAM_FT_HTTP_500        0x00000010

#define NGX_HTTP_UPSTREAM_FT_HTTP_502        0x00000020

#define NGX_HTTP_UPSTREAM_FT_HTTP_503        0x00000040

#define NGX_HTTP_UPSTREAM_FT_HTTP_504        0x00000080

#define NGX_HTTP_UPSTREAM_FT_HTTP_404        0x00000100

#define NGX_HTTP_UPSTREAM_FT_UPDATING        0x00000200

#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK      0x00000400

#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING    0x00000800

#define NGX_HTTP_UPSTREAM_FT_NOLIVE          0x40000000

ngx_http_upstream_next,只要错误类型不是 NGX_HTTP_UPSTREAM_FT_HTTP_404,都认为后端有问题(NGX_PEER_FAILED)

if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {

state = NGX_PEER_NEXT;

} else {

state = NGX_PEER_FAILED;

}

ngx_http_upstream_next 调用RR的peer.free,RR根据state判断刚才接受请求的后端是否健康。

if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) {

u->peer.free(&u->peer, u->peer.data, state);

}

ngx_http_upstream_next 如果超过最大重试次数(默认为后端的个数,每试过一个,就减1),或者proxy设置不允许redispatch,则向客户端返回响应status。

if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {

ngx_http_upstream_finalize_request(r, u, status);

}

proxy 模块的 proxy_next_upstream 配置,在何种情况下将请求redispatch到下一个后端。

刚刚谈到,只要错误类型不是 NGX_HTTP_UPSTREAM_FT_HTTP_404,都认为后端有问题。这里的错误类型包括,连接后端失败,连接,读写后端超时,后端返回了500,502,504等。这个策略是有待商榷的,尤其是读写后端超时也判断为后端不可用。因为某个业务请求,可能因为自身的原因而导致读写超时。注意,在proxy_next_upstream 中指定timeout,http_504 是不同的,前者表示upstream连接,读写后端超时,后者表示后端返回的http code 是504。

实际上健康检查不是必须的,因为redispatch的存在保证了,就算有后端宕机,客户端仍将收到正确的响应。那么我们考虑关掉健康检查。通过upstream 的server配置的max_fails 参数

RR 的peer.get,如果max_fails 为0,则该后端总是可用的(就算它真有问题)。

if (peer->max_fails == 0

|| peer->fails < peer->max_fails)

{

break;

}

因为redispatch的次数,取决于后端的个数,所以后端的个数稍微多一点是有好处的。

下面是一些佐证分析的测试。

upstream test {

server 127.0.0.1:8060 max_fails=0;

server 127.0.0.1:8070 max_fails=0;

server 127.0.0.1:8080 max_fails=0;

server 127.0.0.1:8090 max_fails=0;

}

只有8060,8070是存活的,8080,8090处于不可用状态,这里max_fails=0,关闭了健康检查。

proxy_read_timeout 2;

读超时设为2S。

proxy_next_upstream error timeout;

默认当 error 和 timeout发生时,redispatch。

测试请求的sleep参数指定后端的sleep时间,code参数指定后端返回的http code。根据time和sleep时间的对比,判断重试了几个后端。

time curl "http://127.0.0.1:8099/index.php?sleep=3" -vv

real    0m4.014s

sleep=3,读超时,重试了2个后端。

修改配置 proxy_next_upstream error;

time curl "http://127.0.0.1:8099/index.php?sleep=3" -vv

real    0m2.018s

读超时,不再redispatch,重试了1个后端。

修改配置 proxy_next_upstream error http_504;

time curl "http://127.0.0.1:8099/index.php?sleep=1" -vv

real    0m1.022s

这个是正常请求。

time curl "http://127.0.0.1:8099/index.php?sleep=1&code=504" -vv

real    0m2.023s

让后端返回504,此时nginx会做redispatch,重试了2个后端

但是nginx返回给客户端的是502,不是504,因为所有的后端都返回504,nginx认为后端不可用,返回502.

测试健康检查,关掉redispatch。proxy_next_upstream off;

curl "http://127.0.0.1:8099/index.php?sleep=3" -vv

返回了两次502,两次504。存活的后端返回504,有问题的返回502。

修改 max_fails server 127.0.0.1:8060 max_fails=1; 对8060开启健康检查。

curl "http://127.0.0.1:8099/index.php?sleep=3" -vv

第一轮4次请求,返回两次502,两次504

8080和8090有问题,返回502,8060和8070响应超时,返回504,因为8060开启了健康检查,并且返回了504,所以被标记为不可用。

第二轮4次请求,返回三次502,一次504。8070没有开启健康检查,所以仍然返回504。

根据测试分析,业务请求(sleep 3s,或者 输出 http 504)可以让nginx误以为后端宕了,而这时后端活得好好的。在私有云平台,这个通常不是问题,把超时设大点,不返回5XX错误,可以避免这个问题。但是在公有云平台,这是致命的,因为业务可以编程输出5XX错误。有两种方法应对,一种是关闭健康检查,一种是修改nginx的代码,仅对 NGX_HTTP_UPSTREAM_FT_ERROR 判定为后端有问题。

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

本文永久更新链接地址: https://www.linuxidc.com/Linux/2018-10/154666.htm


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning Python, 5th Edition

Learning Python, 5th Edition

Mark Lutz / O'Reilly Media / 2013-7-6 / USD 64.99

If you want to write efficient, high-quality code that's easily integrated with other languages and tools, this hands-on book will help you be productive with Python quickly. Learning Python, Fifth Ed......一起来看看 《Learning Python, 5th Edition》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具