大家都知道,前段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/ 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的方式,这是最好的结果了。