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 判定为后端有问题。

nginx 健康检查和负载均衡机制分析的更多相关文章

  1. 分析NGINX 健康检查和负载均衡机制

    nginx 是优秀的反向代理服务器,这里主要讲它的健康检查和负载均衡机制,以及这种机制带来的问题.所谓健康检查,就是当后端出现问题(具体什么叫出现问题,依赖于具体实现,各个实现定义不一样),不再往这个 ...

  2. 【翻译】Nginx的HTTP负载均衡

    本文为翻译文,原文地址:http://nginx.org/en/docs/http/load_balancing.html 介绍 将请求负载均衡到多个应用实例是一个常用的技术,它起到优化资源使用率.最 ...

  3. octavia的实现与分析(一)·openstack负载均衡的现状与发展以及lvs,Nginx,Haproxy三种负载均衡机制的基本架构和对比

    [负载均衡] 大量用户发起请求的情况下,服务器负载过高,导致部分请求无法被响应或者及时响应. 负载均衡根据一定的算法将请求分发到不同的后端,保证所有的请求都可以被正常的下发并返回. [主流实现-LVS ...

  4. openstack octavia的实现与分析(一)openstack负载均衡的现状与发展以及lvs,Nginx,Haproxy三种负载均衡机制的基本架构和对比

    [负载均衡] 大量用户发起请求的情况下,服务器负载过高,导致部分请求无法被响应或者及时响应. 负载均衡根据一定的算法将请求分发到不同的后端,保证所有的请求都可以被正常的下发并返回. [主流实现-LVS ...

  5. Nginx/LVS/HAProxy 负载均衡软件的优缺点详解

    Nginx/LVS/HAProxy 负载均衡软件的优缺点详解   Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件,本人都在多个项目中实施过,参考了一些资料,结合自己的一些使用经验 ...

  6. 总结)Nginx/LVS/HAProxy负载均衡软件的优缺点详解

    总结)Nginx/LVS/HAProxy负载均衡软件的优缺点详解 PS:Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件,本人都在多个项目中实施过,参考了一些资料,结合自己的一些使 ...

  7. Nginx/LVS/HAProxy负载均衡软件的优缺点详解【转】

    转自 (总结)Nginx/LVS/HAProxy负载均衡软件的优缺点详解http://www.ha97.com/5646.html PS:Nginx/LVS/HAProxy是目前使用最广泛的三种负载均 ...

  8. (总结)Nginx/LVS/HAProxy负载均衡软件的优缺点详解

    Nginx/LVS/HAProxy负载均衡软件的优缺点详解 PS:Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件,参考了一些资料,结合自己的一些使用经验,总结一下. 一般对负载均 ...

  9. nginx+php负载均衡集群环境中的session共享方案梳理

    在网站使用nginx+php做负载均衡情况下,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态. 下面罗列几种nginx负载均衡 ...

随机推荐

  1. jtemplate使用笔记

    最近的项目中用到了jtemplate, 它是客户端基于javascript的模板引擎,绑定的数据为json对象.以前我在页面上显示数据列表时最喜欢用Repeater控件了,因为它相对与其它几个服务端控 ...

  2. sae-php调试代码,不输出页面

    如果单单使用sae_debug,页面就会输出SAE_DEBUG的信息,所以造成很多问题,例如回复微信服务器的xml,但是不知道就想着调试,结果... 所以怎么解决让调试信息不输出页面呢 看完手册,才知 ...

  3. 解决laravel中环境配置不起作用的方法

    博客已经迁移到www.imyzf.com,本站不再更新,请谅解! laravel有个环境配置选项很好用,在bootstrap/start.php中,曾经百度到这里面加入域名,就可以自动选择环境 $en ...

  4. 求给定数据中最小的K个数

    public class MinHeap { /* * * Top K个问题,求给定数据中最小的K个数 * * 最小堆解决:堆顶元素为堆中最大元素 * * * */ private int MAX_D ...

  5. 【BZOJ】1053: [HAOI2007]反素数ant

    1053: [HAOI2007]反素数ant Description: g(x)表示x的约数个数,反素数:对于任意的i (i < x),均有g(i) < g(x),则x为反素数:现在输入不 ...

  6. 2016031901 - U盘安装ubuntu系统

    使用U盘安装ubuntu系统 01.进入u盘安装 个人使用的是闪迪U盘安装 02. 个人重装ubuntu 03.进入ubuntu安装界面 04.进入语言界面 05.准备安装ubuntu 06.ubun ...

  7. [转]python 之字典{}(Hashmap)

    字典 python里的字典就像java里的HashMap,以键值对的方式存在并操作,其特点如下 通过键来存取,而非偏移量: 键值对是无序的: 键和值可以是任意对象: 长度可变,任意嵌套: 在字典里,不 ...

  8. ASP.Net 添加 Interop for Word, excel 插件

    1:在服务器上安装office的Excel软件. 2:在"开始"->"运行"中输入dcomcnfg.exe启动"组件服务" 3:依次双 ...

  9. javascript移动设备触屏事件

    ontouchstartontouchmoveontouchendontouchcancel 目前移动端浏览器均支持这4个触摸事件: /** * onTouchEvent */ var div = d ...

  10. node.js + gulp用JENKINS作CI编译

    这里还是有点坑,要注意. 安装NODE.JS不说,GULP绿色化也不说. 但要让JENKINS识别环境变量. /etc/profile.... export NODE_HOME=/usr/local/ ...