Nginx自带针对后端节点健康检查功能比较简单,由ngx_http_upstream_module和ngx_http_proxy_module模块的相关指令来完成,通过一定重试机制保证容错和负载均衡。请求到后端节点出现故障时,才会切换到健康节点来提供访问,实际上nginx自带模块不算是健康检查的功能,
简单案列分析
upstream backend {
server 192.168.1.225:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.1.226:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.1.227:8080 backup;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504 invalid_header;
proxy_connect_timeout 1s;
proxy_read_timeout 60s;
proxy_send_timeout 30s;
# ....其他
}
}
weight:
轮询权值Weight值越大,分配到的访问机率越高;默认值为1。
max_fails:
①与后端服务器尝试失败次数,为0则认为服务端一直可用,根据fail_timeout定义时间内,失败的次数达到此处的2次,就认为此服务器不可用。
②不可用的后端在fail_timeout时间内与成功返回2次,则认为服务器恢复。
③何为与服务端通讯失败可通过指令proxy_next_upstream、fastcgi_next_upstream和memcached_next_upstream来配置,控制错误触发的尝试其他节点。
④默认配置时,http_404状态不被认为是失败的尝试。
fail_timeout:
默认值 10s,有两层含义,一是此处30s 时间内最多容许 2 次失败;二是在经历了 2 次失败以后,30s时间内不分配请求来试探到这台服务器。
backup:
备份机器。当其他所有的非backup机器出现故障的时候,才会请求backup机器。
max_conns:
限制同时连接到某台后端服务器的连接数,默认为0即无限制,还是保持默认吧。
proxy_next_upstream说明
这个指令属于ngx_http_proxy_module模块的,指定后端返回什么样的异常响应时,才会将请求转发给其他节点。
语法: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | non_idempotent | off ...;
error # 与服务器建立连接,向其传递请求或读取响应头时发生错误;
timeout # 在与服务器建立连接,向其传递请求或读取响应头时发生超时;
invalid_header # 服务器返回空的或无效的响应;
http_500 # 服务器返回代码为500的响应;
non_idempotent # 当请求类型为(POST,LOCK,PATCH)时,后端检测不会因失败而重试其他后端; 启用此选项是允许重试此类请求;(慎重,POST后端处理慢而超时,而去重试了下一机,可造成重复POST了订单风险)
off # 禁用将请求传递去重试下一个服务器。
此时,还可以通过调节ngx_http_proxy_module 模块中的下面三个指令,调整值来发现不健康节点,进而将请求往健康节点转移。proxy模块默认的读取超时时间是60s。
proxy_connect_timeout : 后端服务器连接的超时时间,发起握手包seq等候seq+ack响应的超时时间。
proxy_read_timeout : 定义从后端服务器读取响应超时,排队之中等候处理(超时重试可能引发重复请求)
proxy_send_timeout : 定义后端服务器数据回传时间,即规定时间之内后端服务器必须传完所有数据,否则nginx将断开这个连接。
proxy_connect_timeout 重点说明下:
在高速内网二层中:
1. 后端的服务器已经关机/断网,当number等于1s时,请求轮询到这机器时,请求建立通讯,共发2次ARP广播都没回应,就放弃了而去重试别的后端,(发了一次没回应马上发其他后端,再发一次没回应就放弃)。
2. 当number等于4-60s之间或不使用这指令,会连续发送4次ARP广播寻找它,都没回应才放弃而重试其他后端,前端页面卡住状态大概3秒,如果下一个后端也是这个断网状态,等待时间就累加了。
3. 如与后端服务器是经三层转发的内网,即使已经断网/关机,这三层网关(看实际环境)会很快回应找不到主机而重试其他后端。
4. 如后端的服务器仅端口程序虽然已经关闭,如tomcat进程退出,这还能与后端ARP通信和TCP握手通信,很快得到了回应seq+ack,而去重试别的,这前端页面不用等待长的时间。
高延迟的网络中,并在非二层网络通信,因长时间得不到握手包seq+ack回应,是真实地受number值影响重试时间。
总结: 就怕那些死机,断网的,所以proxy_connect_timeout 指令存在还是有必要的,值不要过高。
proxy_connect_timeout 2s;
proxy_read_timeout 60s;
proxy_send_timeout 30s;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_404;
三个时间,同时还设置了proxy_next_upstream保证服务器的高可用;
因结算系统高峰时存在处理缓慢,在结算的时候处理时间过长了,导致超过了以上值时间,导致upstream超时,转到下一台web服务器处理了,但是之前的进程还在跑,所以结算了多次;
1.针对部分结算的接口,考虑将proxy_next_upstream设置为off
2.其他接口依然设置为proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_404;保证服务器的高可用。
语法 proxy_next_upstream_tries number; 例子 proxy_next_upstream_tries 0;
1.当number等于1时,表示只负载一台机器,超时也返回,不去重试其他,如果成功即获得成功的响应;再下一请求的轮询到不健康的,那也是返回超时或错误信息了;
2.当存在多台后端,实际只有一台是正常健康,如number为2,则表示如第一请求遇到异常后端超时或错误会去轮询重试下一台机,这台依然不行时,那直接返回了,不再去重试其他后端;
3.因自带的健康检测是基于请求失败次数来确定后端的剔除,所以即使重试第二台遇上健康的,其他都判定为不健康剔除了,但下一个时间请求也会去检测不健康那些,当number数比后端不健康数少,就呵呵了;
自带后端健康判断满足一定的业务需求,如果后端有不健康节点,负载均衡器依然会先把该请求转发给该不健康节点,过程经历尝试max_fails次,再判断为不健康后端,这样就会浪费一次转发,可能会造成响应时间过久。