大家都知道,前段nginx做反代,如果后端服务器宕掉的话,nginx是不能把这台realserver提出upstream的,所以还会有请求转发到后端的这台realserver上面去,虽然nginx可以在localtion中启用proxy_next_upstream来解决返回给用户的错误页面,方法在:http://www.linuxyan.com/web-server/67.html,大家可以参考一下,但这个还是会把请求转发给这台服务器的,然后再转发给别的服务器,这样就浪费了一次转发,这次借助与淘宝技术团队开发的nginx模快nginx_upstream_check_module来检测后方realserver的健康状态,如果后端服务器不可用,则所以的请求不转发到这台服务器。
首先去这里下载nginx的模块,并解压他
wget https://codeload.github.com/yaoweibin/nginx_upstream_check_module/zip/master
unzip master
打补丁之前我们有几个库需要安装一下,下面给出所有的安装:
# 安装zlib第三方库
wget http://dl.download.csdn.net/down10/20131007/9be6c56fd26170af17babe1769b906f5.gz?response-content-disposition=attachment%3Bfilename%3D%22zlib-1.2.8.tar.gz%22&OSSAccessKeyId=9q6nvzoJGowBj4q1&Expires=1494242459&Signature=QYeMKOSBbyvWz%2FgLl5AsEXR9Yw0%3D
tar zxvf zlib-1.2.8.tar.gz
cd zlib-1.2.8
./configure
make && make install
# 安装pcre第三方库
wget https://jaist.dl.sourceforge.net/project/pcre/pcre/8.40/pcre-8.40.tar.gz
tar zxvf pcre-8.40.tar.gz
cd pcre-8.40
./configure
make && make install
# 安装c++编译环境
yum install -y gcc gcc-c++
下面是nginx打上模块补丁的安装:
$ wget http://nginx.org/download/nginx-1.7.4.tar.gz
$ tar -xzvf nginx-1.7.4.tar.gz
$ cd /nginx-1.7.4
$ patch -p1 < /home/soft/nginx_upstream_check_module-master/check_1.7.2+.patch
$ ./configure --prefix=/home/www/nginx --user=nobody --group=nobody --with-http_stub_status_module --with-http_realip_module --add-module=/root/nginx_upstream_check_module-master
$ make
$ make install
## 注:因nginx版本更新,1.2以上版本的nginx,补丁为check_1.2.1+.patch
之后在nginx.conf配置文件里面的upstream加入健康检查,如下:
upstream operationApi {
server 10.25.170.215:17011;
server 10.25.170.216:17011;
check interval=5000 rise=2 fall=2 timeout=3000 type=http;
check_http_send "GET /operationApi/login.jsp HTTP/1.0\r\n HOST na.szcq18.com\r\n\r\n";
}
这里下面加的这句话我解释下,interval检测间隔时间,单位为毫秒,rsie请求2次正常的话,标记此realserver的状态为up,fall表示请求5次都失败的情况下,标记此realserver的状态为down,timeout为超时时间,单位为毫秒。
- interval:向后端发送的健康检查包的间隔ms。
- fall(fall_count): 如果连续失败次数达到fall_count,服务器就被认为是down。
- rise(rise_count): 如果连续成功次数达到rise_count,服务器就被认为是up。
- timeout: 后端健康请求的超时时间。
- default_down: 设定初始时服务器的状态,如果是true,就说明默认是down的,如果是false,就是up的。默认值是true,也就是一开始服务器认为是不可用,要等健康检查包达到一定成功次数以后才会被认为是健康的。
- type:健康检查包的类型,现在支持以下多种类型
- tcp:简单的tcp连接,如果连接成功,就说明后端正常。
- ssl_hello:发送一个初始的SSL hello包并接受服务器的SSL hello包。
- http:发送HTTP请求,通过后端的回复包的状态来判断后端是否存活。
- mysql: 向mysql服务器连接,通过接收服务器的greeting包来判断后端是否存活。
- ajp:向后端发送AJP协议的Cping包,通过接收Cpong包来判断后端是否存活。
- port: 指定后端服务器的检查端口。你可以指定不同于真实服务的后端服务器的端口,比如后端提供的是443端口的应用,你可以去检查80端口的状态来判断后端健康状况。默认是0,表示跟后端server提供真实服务的端口一样。
①、主要定义好type。由于默认的type是tcp类型,因此假设你服务启动,不管是否初始化完毕,它的端口都会起来,所以此时前段负载均衡器为认为该服务已经可用,其实是不可用状态。
②、注意check_http_send值的设定。由于它的默认值是”GET / HTTP/1.0\r\n\r\n”。假设你的应用是通过http://ip/name访问的,那么这里你的check_http_send值就需要更改为”GET /name HTTP/1.0\r\n\r\n”才可以。
针对采用长连接进行检查的,这里增加keep-alive请求头,即”HEAD /name HTTP/1.1\r\nConnection: keep-alive\r\n\r\n”。
如果你后端的tomcat是基于域名的多虚拟机,此时你需要通过check_http_send定义host,不然每次访问都是失败,范例:check_http_send “GET /exchange/index.jsp HTTP/1.0\r\n HOST na.szcq18.com\r\n\r\n”;
在server段里面可以加入查看realserver状态的页面
location /nstatus {
check_status;
access_log off;
#allow SOME.IP.ADD.RESS;
#deny all;
}
这个时候打开nstatus这个页面就可以看到当前realserver的状态了,
如下图:
A.B 两台realserver都正常的情况下
其中一台realserver故障的情况下
注意:Nginx的启动命令在/usr/local/niginx/sbin目录下;
下面给出一个我配置的相关的检查负载均衡的状态配置文件:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
error_log /var/log/nginx/error.log warn;
pid /home/www/nginx/logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream backend {
server 120.24.165.15:80 weight=3 max_fails=3 fail_timeout=30s ;
server 120.76.97.203:80 weight=1 max_fails=1 fail_timeout=30s ;
check interval=3000 rise=2 fall=5 timeout=1000;
}
server {
listen 8078;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location /nstatus {
check_status;
access_log on;
#allow SOME.IP.ADD.RESS;
#deny all;
}
location / {
proxy_pass http://backend ;
proxy_next_upstream error timeout invalid_header http_404;
proxy_connect_timeout 2s; #后端服务器连接的超时时间_发起握手等候响应超时时间
proxy_read_timeout 2s; #后端服务器处理请求的时间
#nginx反向代理配置时,一般会添加下面的配置:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#weight:轮询权值也是可以用在ip_hash的,默认值为1
#max_fails:允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
#fail_timeout:有两层含义,一是在 30s 时间内最多容许 2 次失败;二是在经历了 2 次失败以后,30s时间内不分配请求到这台服务器。
#backup:备份机器。当其他所有的非backup机器出现故障的时候,才会请求backup机器
#max_conns: 限制同时连接到某台后端服务器的连接数,默认为0即无限制。因为queue指令是commercial,所以还是保持默认吧。
#proxy_next_upstream:这个指令属于 http_proxy 模块的,指定后端返回什么样的异常响应时,使用另一个realserver
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
这里,我警告大家一点,如果你使用了加权轮询的方式做了负载均衡,那么,他不会保证session的获取保存方式,引发的为题可想而知,比如你的验证码不可以使用了,在登录跳转后,如果状态是基于session来检查登录状态,那么view上你是A服务,登录请求到了B服务,跳转的时候又是A服务,发现你没有登录,又跳回到了B服务,B服务发现登录了,重新跳转毁了A服务,结果自己想吧,重定向次数过多,拒绝了你的请求服务,请大家参考一下吧,最好的方式是使用IP_HASH的方式,这是最好的结果了。