Nginx1.12.1后端节点健康检测+会话保持方案

来源:互联网 发布:ubuntu源无法使用 编辑:程序博客网 时间:2024/05/11 03:57

Nginx社区版,也就是我们能从官网免费下载到源码并且编译的版本,不是一个合格的商业负载均衡器。为什么这么说呢,是因为社区版在反向代理负载均衡这个功能上,很多重要的工作的解决方案是非常幼稚或者说是不成熟的。主要表现在两个方面,后端被负载均衡Web服务器的健康监测和Session回话保持功能。

首先说回话保持,nginx官方给出的解决方案是ip_hash,也就是根据访问客户的源IP地址进行分发。表看起来没什么问题,实际应用几乎不可行。比如为学校做一个选课系统,服务器放在服务网段,学生在普通网段,两个网段互通全靠NAT,Nginx收到的IP全都是同一个源IP,那么这个负载均衡没有就没有生效。

其次是后端健康检测,Nginx官方给出的解决方案是

server localhost:9191 max_fails=1 fail_timeout=40s;

意思就是如果9191这个端口某次连接超时或者失败max_fails次,就判定为不可用,然后等待fail_timeout这么长时间之后自动认为其可用,不管到底真的修复了没有。然后再次重试max_fails次。这还不算最坑爹的,更麻烦的是在Nginx上你无法查看各个后端节点的状态,不知道哪台宕机了或者卡了不好用了。如果你后端有一百台被负载均衡的服务器,光检查可用性这一点Nginx社区版就完败。


再就是连接和流量的统计功能,也适用于检查后端健康情况和当前的并发连接数的,这个功能社区版默认还是没有的,需要在编译时添加一个官方支持的模块

--with-http_stub_status_module

可即使添加了这个模块,你看到的也就是下面这个简陋到爆的状态监控页面


从这个页面中,谁能告诉我哪台后端服务器宕机了,谁又能告诉我哪台后端服务器卡了,又怎么能知道哪台后端服务器的压力最大,哪台压力最轻?这些在Nginx都无从获取。

那么在对比一下同样是免费开源的专门做反向代理负载均衡的HAProxy的后台页面


每个节点的健康状况,运行时间,宕机时间,当前连接数,最大连接数,总连接数,数据进出流量是不是一目了然,马上就可以看到这个服务器的健康状况和处理能力。能看到现在哪台服务器负担最重,可以及时调整策略。提前防范风险。

再看看收费版的NGINX+的监控页面



显示的内容和HAProxy差不多,但是是不是感觉更高大上了。

所以说珍爱生命,远离社区版。

那么我们应该怎么办呢?要么用成熟稳定且免费开源的HAProxy做反向代理的负载均衡,要么缴纳2500美元一年购买商业版的NGINX plus。或者使用阿里巴巴为淘宝修改过的Nginx——tengine。不过tengine几乎一年才更新一次,好在一个月以前刚刚发布了2017版,支持了Nginx-1.8.1的全部特性。可是1.9之后的重要功能,比如TCP和UDP的负载均衡就没有了。

下面来看看tengine的后台监控页面


在这上面起码能看到哪个后端服务器宕机了,但是相对于HAProxy和Nginx plus,这个还是无法观测每台服务器的连接数和流量,不能观测负载。


那么该如何选择负载均衡器呢,一般来说运维有如下的需求:

1、基于Cookie的回话保持

2、可以后台监控服务器的负载状态和健康状况,主动对后端服务器进行健康检查

3、支持以最小连接数为基准的负载均衡分发策略


对于HAProxy来说,1,2,3点全部都可以实现,而且全部是官方支持,不需要打补丁,直接在apt源或者yum源上安装就可以全部实现。据网上的资料,HAProxy的并发数还要高于NGINX

对于Tengine来说,1,2,3也可以支持,但是1,3不能同时支持。也就是说如果使用Cookie作为会话保持策略,那就不能再以最少连接数作为分发策略了,只能使用轮训(round_robin),这样的话很容易出现某些服务器占用超级高,然后其他服务器几乎没有负载的糟糕情况。且后台监控页面比较简陋,看不到具体每台节点的负载情况。

对于Nginx puls来说,1,2,3都可以支持,但是由于价格太过昂贵,所以我也没试过其真实的效果。

对于硬件负载均衡器F5或A10来说,1,2,3都可以支持,而且基本没什么大问题。


综上所述,HAProxy是支持最全面,成本最低的方案。而且HAProxy还可以支持TCP连接的负载均衡,这一点是NGINX社区版和plus在1.9版本之后才实现的功能。Tengine由于基础版本才1.8.1所以并不支持。

但是如果公司里出现了脑残项目经理,非要使用NGINX社区版怎么办?

对于第一点,Cookie和HEAD的回话保持,我的上一篇博客NGINX基于Cookie和Header的负载均衡会话保持 里介绍了如何添加Tengine开源的nginx-sticky-module-ng实现回话保持功能,但是可惜的一点是如果使用了该回话保持方案,就不能使用最少连接数(least_conn)的分发策略,只能使用轮训(round_robin)分发策略,这样对于服务器的均衡是很不利的

对于第二点,Tengine同样开源了一个模块nginx_upstream_check_module,可以把这个模块安装到Nginx社区版进行使用。

对于第三点,社区版支持least_conn,只不过不能和cookie回话保持共用。


下面就介绍一下如何把Tengine的nginx_upstream_check_module移植到Nginx 1.12.1版本上,并添加nginx-sticky-module-ng模块实现cookie的回话保持功能。

大概分为如下几个步骤

1、下载nginx_upstream_check_module源码,并对NGINX源码打补丁包

2、下载nginx-sticky-module-ng源码,并打上上面下载的nginx_upstream_check_module源码提供的补丁包

3、在configue中添加上面的两个model进行编译。

首先需要下载nginx_upstream_check_module的源码,地址:https://github.com/yaoweibin/nginx_upstream_check_module 今年的8月3号已经添加了Nginx 1.12.1的补丁包

直接克隆这个项目到本地Nginx1.12.1源码目录下


然后下载nginx-sticky-module-ng的源码,地址:https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/downloads/

然后解压到Nginx1.12.1源码目录下,之后Nginx的源码目录结构如下

[root@oa-app nginx-1.12.1]# ls -alt总用量 760drwxr-xr-x. 11 alex alex   4096 10月 25 08:38 .drwxrwxr-x.  4 alex alex   4096 10月 24 17:31 objs-rw-rw-r--.  1 alex alex    376 10月 24 17:30 Makefiledrwxr-xr-x   4 root root   4096 10月 24 17:26 nginx-goodies-nginx-sticky-module-rw-r--r--   1 root root   8060 10月 24 17:23 check_1.12.1+.patch-rw-r--r--   1 root root   1709 10月 24 17:23 nginx-sticky-module.patchdrwx---rwx. 17 alex alex   4096 10月 18 16:35 ..drwxr-xr-x.  6 alex alex   4096 10月 13 16:11 autodrwxr-xr-x.  2 alex alex   4096 10月 13 16:11 confdrwxr-xr-x.  4 alex alex   4096 10月 13 16:11 contribdrwxr-xr-x.  9 alex alex   4096 10月 13 16:11 srcdrwxr-xr-x.  2 alex alex   4096 10月 13 16:11 htmldrwxr-xr-x.  2 alex alex   4096 10月 13 16:11 mandrwxr-xr-x   6 root root   4096 8月   3 19:50 nginx_upstream_check_module-master-rw-r--r--.  1 alex alex 277349 7月  11 21:24 CHANGES-rw-r--r--.  1 alex alex 422542 7月  11 21:24 CHANGES.ru-rwxr-xr-x.  1 alex alex   2481 7月  11 21:24 configure-rw-r--r--.  1 alex alex   1397 7月  11 21:24 LICENSE-rw-r--r--.  1 alex alex     49 7月  11 21:24 README

下面要做的就是给Nginx和sticky模块打上upstream check的补丁包。

在Nginx源码目录下,执行

  patch -p1 < ./nginx_upstream_check_module-master/check_1.12.1+.patch  patching file src/http/modules/ngx_http_upstream_hash_module.cpatching file src/http/modules/ngx_http_upstream_ip_hash_module.cpatching file src/http/modules/ngx_http_upstream_least_conn_module.cpatching file src/http/ngx_http_upstream_round_robin.cpatching file src/http/ngx_http_upstream_round_robin.h

然后cd到nginx-sticky-module-ng源码目录下,再执行

  patch -p0 < ../nginx-sticky-module.patch   patching file ngx_http_sticky_module.cHunk #1 succeeded at 15 with fuzz 2 (offset 5 lines).Hunk #2 succeeded at 304 (offset 12 lines).Hunk #3 succeeded at 330 (offset 12 lines).Hunk #4 succeeded at 352 (offset 12 lines).
这样两个补丁就打完了,然后配置一下configue,添加TCP和UDP负载均衡的支持,因为这是选择1.12.1版本的一个重要目的

./configure --with-http_stub_status_module --with-http_ssl_module --with-stream --with-http_realip_module --add-module=./nginx-goodies-nginx-sticky-module --add-module=./nginx_upstream_check_module-master

最后就可以使用make && make install 编译了。


对于1.12.1版本,如果你觉得打补丁包和下载补丁包太麻烦,可以使用我打包好的Nginx 1.12.1源码(打好upstream_check补丁)+nginx_upstream_check_module源码+nginx-sticky-module-ng源码(打好upstream_check补丁)

只需执行

./configure --with-http_stub_status_module --with-http_ssl_module --with-stream --with-http_realip_module --add-module=./nginx-goodies-nginx-sticky-module --add-module=./nginx_upstream_check_module-master
再make就可以了

下载地址:http://download.csdn.net/download/lvshaorong/10038654


最后再介绍一下,tengine和打了tengin upstream_check补丁的社区版Nginx对于后端的健康监测有多种方式,主要用的就是TCP和HTTP方式。

默认为TCP方式,配置为

upstream emobile {sticky;        server 127.0.0.1:22;server 127.0.0.1:8088;check interval=3000 rise=2 fall=5 timeout=1000    }

这个upstream同时配置了基于cookie的回话保持和TCP的健康检测。

这个检测每3秒执行一次,如果5次都没有成功就认定这个服务器不可达,超时时间为1秒。设定为不可达之后,请求就不会再向这个服务器发送了,但是仍然每隔3秒检测一下这个服务器的健康度,如果两次连续检查都成功就设定这个服务器为健康,然后再重新把后面的请求向这个服务器发送,实现和HAProxy一样的功能,语法也类似。


但是TCP检测有一个不好处,就是只要这个端口可以telnet通就认定为可用,如上面我把SSH的22端口和tomcat的8088端口放在一起,nginx认为两个服务器都是健康的,于是平均的向他们发送请求,所以这样总有一半的用户请求到的是404。

那么如何避免这种问题呢,可以使用HTTP模式,让NGINX主动去GET请求一个页面,如果请求的返回码为2XX,3XX就认定服务器是好用的,如下

upstream emobile {sticky;        server 127.0.0.1:22;server 127.0.0.1:8088;check interval=3000 rise=2 fall=5 timeout=1000 type=http;        check_http_send "GET /login.do HTTP/1.0\r\n\r\n";        check_http_expect_alive http_2xx http_3xx;    }

上面的配置Nginx会每3秒钟请求一次127.0.0.1:8088/login.do这个页面,并判断HTTP状态码。因为SSH 22端口请求结果肯定是404,所以Nginx就会认为这个不可达,这样就可以避免TCP模式的缺陷。

这个check_http_send后面可以接好多种url,最常用的就是GET,还有POST和HEAD,如果你想检测特定某个页面,可以访问一下该页面然后查找access log,查看相应的请求,如下面这段log就可以拷贝出来,检测特定页面是不是通畅。

 [25/Oct/2017:16:57:45 +0800] 36.10.56.102:34076 [200]  36.10.48.102  "GET /mobile/plugin/hrm/hrminterface.jsp?cmd=getPasswordComplexity&languageid=zh-Hans-CN HTTP/1.1" "-" "\xC3\xA7\xC2\xBD\xC2\x91\xC3\xA4\xC2\xB8\xC2\x8A\xC3\xA5\xC2\x8A\xC2\x9E\xC3\xA5\xC2\x85\xC2\xAC 6.10 (iPhone; iOS 11.0.3; zh_CN)" "36.10.201.254, 36.10.48.102" abcdG2O6Lwjtl6fjCIs9v++0c1a45aa3eaad72623bb05d0f35c3577 37





原创粉丝点击