转:http://www.tuicool.com/articles/Z3muQb
1. 摘要
(1) 结论
详细描述了 nginx 记录失效节点的 6 种状态 (time out 、 connect refuse 、 500 、 502 、 503 、 504 ,后四项 5XX 需要配置 proxy_next_upstream 中的状态才可以生效 ) 、失效节点的触发条件和节点的恢复条件、所有节点失效后 nginx 会进行恢复并进行重新监听。
(2) Nginx 负载均衡方式介绍
Nginx 的负载均衡方式一共有 4 种: rr( 轮询模式 ) 、 ip_hash 、 fair 、 url_hash 。
(3) Ngxin 负载均衡和相关反向代理配置内容
Nginx 负载均衡和与容错相关的反向代理的配置。
(4) 获取后端流程
后端 server 的自动容错流程图。
(5) 测试环境和测试结果
针对几种错误方式进行自动容错测试。
2. 结论
(1) nginx 判断节点失效状态
Nginx 默认判断失败节点状态以 connect refuse 和 time out 状态为准,不以 HTTP 错误状态进行判断失败,因为 HTTP 只要能返回状态说明该节点还可以正常连接,所以 nginx 判断其还是存活状态;除非添加了 proxy_next_upstream 指令设置对 404 、 502 、 503 、 504 、 500 和 time out 等错误进行转到备机处理,在 next_upstream 过程中,会对 fails 进行累加,如果备用机处理还是错误则直接返回错误信息(但 404 不进行记录到错误数,如果不配置错误状态也不对其进行错误状态记录),综述, nginx 记录错误数量只记录 timeout 、 connect refuse 、 502 、 500 、 503 、 504 这 6 种状态, timeout 和 connect refuse 是永远被记录错误状态,而 502 、 500 、 503 、 504 只有在配置 proxy_next_upstream 后 nginx 才会记录这 4 种 HTTP 错误到 fails 中,当 fails 大于等于 max_fails 时,则该节点失效;
(2) nginx 处理节点失效和恢复的触发条件
nginx 可以通过设置 max_fails (最大尝试失败次数)和 fail_timeout (失效时间,在到达最大尝试失败次数后,在 fail_timeout 的时间范围内节点被置为失效,除非所有节点都失效,否则该时间内,节点不进行恢复)对节点失败的尝试次数和失效时间进行设置,当超过最大尝试次数或失效时间未超过配置失效时间,则 nginx 会对节点状会置为失效状态, nginx 不对该后端进行连接,直到超过失效时间或者所有节点都失效后,该节点重新置为有效,重新探测;
(3) 所有节点失效后 nginx 将重新恢复所有节点进行探测
如果探测所有节点均失效,备机也为失效时,那么 nginx 会对所有节点恢复为有效,重新尝试探测有效节点,如果探测到有效节点则返回正确节点内容,如果还是全部错误,那么继续探测下去,当没有正确信息时,节点失效时默认返回状态为 502 ,但是下次访问节点时会继续探测正确节点,直到找到正确的为止。
3. nginx 负载均衡
Nginx 的负载均衡方式一共有 4 种: rr( 轮询模式 ) 、 ip_hash 、 fair 、 url_hash ;
Nginx 自带的 2 种负载均衡为 rr 和 ip_hash , fair 和 url_hash 为第三方的插件, nginx 在不配置负载均衡的模式下,默认采用 rr 负载均衡模式。
l RR 负载均衡模式:
每个请求按时间顺序逐一分配到不同的后端服务器,如果超过了最大失败次数后( max_fails, 默认 1 ),在失效时间内 (fail_timeout ,默认 10 秒 ) ,该节点失效权重变为 0 ,超过失效时间后,则恢复正常,或者全部节点都为 down 后,那么将所有节点都恢复为有效继续探测,一般来说 rr 可以根据权重来进行均匀分配。
l Ip_hash 负载均衡模式:
每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题,但是 ip_hash 会造成负载不均,有的服务请求接受多,有的服务请求接受少,所以不建议采用 ip_hash 模式, session 共享问题可用后端服务的 session 共享代替 nginx 的 ip_hash 。
l Fair (第三方)负载均衡模式:
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
l url_hash (第三方)负载均衡模式:
和 ip_hash 算法类似,是对每个请求按 url 的 hash 结果分配,使每个 URL 定向到一个同 一个后端服务器,但是也会造成分配不均的问题,这种模式后端服务器为缓存时比较好。
4. Nginx 负载均衡配置
Nginx 的负载均衡采用的是 upstream 模块
其中默认的采用的负载均衡模式是轮询模式 rr(round_robin), 具体配置如下:
1) 指令:
ip_hash
语法: ip_hash
默认值: none
使用字段: upstream
这个指令将基于客户端连接的 IP 地址来分发请求。 哈希的关键字是客户端的 C 类网络地址,这个功能将保证这个客户端请求总是被转发到一台服务器上,但是如果这台服务器不可用,那么请求将转发到另外的服务器上,这将保证某个客户端有很大概率总是连接到一台服务器。 无法将权重( weight )与 ip_hash 联合使用来分发连接。如果有某台服务器不可用,你必须标记其为 “down” ,如下例 :
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
server
语法: server name [parameters]
默认值: none
使用字段: upstream
指定后端服务器的名称和一些参数,可以使用域名, IP ,端口,或者 unix socket 。如果指定为域名,则首先将其解析为 IP 。
l weight = NUMBER - 设置服务器权重,默认为 1 。
l max_fails = NUMBER - 在一定时间内(这个时间在 fail_timeout 参数中设置)检查这个服务器是否可用时产生的最多失败请求数,默认为 1 ,将其设置为 0 可以关闭检查,这些错误在 proxy_next_upstream 或 fastcgi_next_upstream ( 404 错误不会使 max_fails 增加)中定义。
l fail_timeout = TIME - 在这个时间内产生了 max_fails 所设置大小的失败尝试连接请求后这个服务器可能不可用,同样它指定了服务器不可用的时间(在下一次尝试连接请求发起之前),默认为 10 秒, fail_timeout 与前端响应时间没有直接关系,不过可以使用 proxy_connect_timeout 和 proxy_read_timeout 来控制。
l down - 标记服务器处于离线状态,通常和 ip_hash 一起使用。
l backup - (0.6.7 或更高 ) 如果所有的非备份服务器都宕机或繁忙,则使用本服务器(无法和 ip_hash 指令搭配使用)。
示例配置
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
注意:如果你只使用一台上游服务器, nginx 将设置一个内置变量为 1 ,即 max_fails 和 fail_timeout 参数不会被处理。 结果:如果 nginx 不能连接到上游,请求将丢失。 解决:使用多台上游服务器。
upstream
语法: upstream name { … }
默认值: none
使用字段: http
这个字段设置一群服务器,可以将这个字段放在 proxy_pass 和 fastcgi_pass 指令中作为一个单独的实体,它们可以可以是监听不同端口的服务器,并且也可以是同时监听 TCP 和 Unix socket 的服务器。 服务器可以指定不同的权重,默认为 1 。 示例配置
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
请求将按照轮询的方式分发到后端服务器,但同时也会考虑权重。 在上面的例子中如果每次发生 7 个请求, 5 个请求将被发送到 backend1.example.com ,其他两台将分别得到一个请求,如果有一台服务器不可用,那么请求将被转发到下一台服务器,直到所有的服务器检查都通过。如果所有的服务器都无法通过检查,那么将返回给客户端最后一台工作的服务器产生的结果。
2) 变量
版本 0.5.18 以后,可以通过 log_module 中的变量来记录日志:
log_format timing '$remote_addr - $remote_user [$time_local] $request '
'upstream_response_time $upstream_response_time '
'msec $msec request_time $request_time';
log_format up_head '$remote_addr - $remote_user [$time_local] $request '
'upstream_http_content_type $upstream_http_content_type';
l $upstream_addr
前端服务器处理请求的服务器地址
l $upstream_cache_status
0.8.3 版本中其值可能为:
MISS
EXPIRED - expired 。请求被传送到后端。
UPDATING - expired 。由于 proxy/fastcgi_cache_use_stale 正在更新,将使用旧的应答。
STALE - expired 。由于 proxy/fastcgi_cache_use_stale ,后端将得到过期的应答。
HIT
l $upstream_status
前端服务器的响应状态。
l $upstream_response_time
前端服务器的应答时间,精确到毫秒,不同的应答以逗号和冒号分开。
l $upstream_http_$HEADER
随意的 HTTP 协议头,如: $upstream_http_host
l $upstream_http_host
3) Proxy 指令:
proxy_next_upstream
语法 : proxy_next_upstream
[error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off]
默认值 : proxy_next_upstream error timeout
使用字段 : http, server, location
确定在何种情况下请求将转发到下一个服务器:
error - 在连接到一个服务器,发送一个请求,或者读取应答时发生错误。
timeout - 在连接到服务器,转发请求或者读取应答时发生超时。
invalid_header - 服务器返回空的或者错误的应答。
http_500 - 服务器返回 500 代码。
http_502 - 服务器返回 502 代码。
http_503 - 服务器返回 503 代码。
http_504 - 服务器返回 504 代码。
http_404 - 服务器返回 404 代码。
off - 禁止转发请求到下一台服务器。
转发请求只发生在没有数据传递到客户端的过程中。
其中记录到 nginx 后端错误数量的有 500 、 502 、 503 、 504 、 timeout , 404 不记录错误。
proxy_connect_timeout
语法 : proxy_connect_timeout timeout_in_seconds
默认值 : proxy_connect_timeout 60s
使用字段 : http, server, location
指定一个连接到代理服务器的超时时间,单位为秒,需要注意的是这个时间最好不要超过 75 秒。 这个时间并不是指服务器传回页面的时间(这个时间由 proxy_read_timeout 声明)。如果你的前端代理服务器是正常运行的,但是遇到一些状况(例如没有足够的线程去处理请求,请求将被放在一个连接池中延迟处理),那么这个声明无助于服务器去建立连接。 可以通过指定时间单位以免引起混乱,支持的时间单位有 ”s”( 秒 ), “ms”( 毫秒 ), “y”( 年 ), “M”( 月 ), “w”( 周 ), “d”( 日 ), “h”( 小时 ), 和 “m”( 分钟 ) 。 这个值不能大于 597 小时。
proxy_read_timeout
语法 : proxy_read_timeout time
默认值 : proxy_read_timeout 60s
使用字段 : http, server, location
决定读取后端服务器应答的超时时间,单位为秒,它决定 nginx 将等待多久时间来取得一个请求的应答。超时时间是指完成了两次握手后并且状态为 established 的超时时间。 相对于 proxy_connect_timeout ,这个时间可以扑捉到一台将你的连接放入连接池延迟处理并且没有数据传送的服务器,注意不要将此值设置太低,某些情况下代理服务器将花很长的时间来获得页面应答(例如如当接收一个需要很多计算的报表时),当然你可以在不同的 location 里面设置不同的值。 可以通过指定时间单位以免引起混乱,支持的时间单位有 ”s”( 秒 ), “ms”( 毫秒 ), “y”( 年 ), “M”( 月 ), “w”( 周 ), “d”( 日 ), “h”( 小时 ), 和 “m”( 分钟 ) 。 这个值不能大于 597 小时。
proxy_send_timeout
语法 : proxy_send_timeout seconds
默认值 : proxy_send_timeout 60s
使用字段 : http, server, location
设置代理服务器转发请求的超时时间,单位为秒,同样指完成两次握手后的时间,如果超过这个时间代理服务器没有数据转发到被代理服务器, nginx 将关闭连接。 可以通过指定时间单位以免引起混乱,支持的时间单位有 ”s”( 秒 ), “ms”( 毫秒 ), “y”( 年 ), “M”( 月 ), “w”( 周 ), “d”( 日 ), “h”( 小时 ), 和 “m”( 分钟 ) 。 这个值不能大于 597 小时。
5. 获取后端流程
GET_RR_PEER : 通过 RR 算法获取后端流程
K: 是判断 peer 是否宕机和判断失效状态算法
FAIL: 尝试次数用尽有,跳转到失败流程,如果有备机,备机再尝试监听,如果监听失败则返回 NGX_BUSY, 成功则返回当前状态。
6. 测试环境
操作系统: centos5.6
Cpu:16 核
内存: 32g
Web 服务器 :nginx
Web 应用服务器: tomcat(2 台 )
7. 测试结果
l 设置 tomcat1 超时时间,造成超时状态(总有一台 server 为有效状态):
Tomcat1 的 connectionTimeout 设置为 -1 ,永远超时, nginx 设置 tomcat1 和 tomcat2 权重为 10 , tomcat1 的 max_fails 为 10 , fail_timeout=120 ;在连接 tomcat1 的 10 次后,返回给 nginx 为 10 次超时, ngxin 判断 tomcat1 为失效,然后将 tomcat1 超时时间恢复为 1000 重新启动 tomcat1 ,在这段时间内 nginx 判断 tomcat1 还是失效状态,所以在 2 分钟后, nginx 继续监听到 tomcat1 正常后,那么 nginx 会将 tomcat1 判断为有效,将连接继续均匀分配到 2 个 tomcat 上。
l 设置 tomcat1 连接数量,造成超时状态(总有一台 server 为有效状态):
Tomcat1 的线程数量设置为 1 , nginx 设置 tomcat1 和 tomcat2 权重为 10 , tomcat1 的 max_fails 为 10 , fail_timeout=120 ;在连接 tomcat1 超过线程接受数量后, tomcat1 会返回超时状态,在返回给 nginx10 次超时状态后, ngxin 判断 tomcat1 为失效,然后将 tomcat 线程数量恢复为 700, 重新启动 tomcat1 ,在这段时间内 nginx 判断 tomcat1 还是失效状态,超过 2 分钟失效后, nginx 继续监听到 tomcat1 正常后,那么 nginx 会将 tomcat1 判断为有效,将连接继续均匀分配到 2 个 tomcat 上。
l 设置 tomcat1 关闭,造成拒绝状态(总有一台 server 为有效状态):
Tomcat1 为关闭, nginx 设置 tomcat1 和 tomcat2 权重为 10 , tomcat1 的 max_fails 为 10 , fail_timeout=120 ;在连接 tomcat1 的 10 次后, nginx 收到 tomcat1 返回 connect refuse 状态, ngxin 判断 tomcat1 为失效,然后重新启动 tomcat1 ,在这段时间内 nginx 判断 tomcat1 还是失效状态,超过 2 分钟失效后, nginx 继续监听到 tomcat1 正常后,那么 nginx 会将 tomcat1 判断为有效,将连接继续均匀分配到 2 个 tomcat 上。
l 设置 tomcat1 在 nginx1 标记失效, tomcat1 恢复正常,在 nginx 失效范围内,将全部服务变为失效,然后重启:
Tomcat1 为关闭, nginx 设置 tomcat1 和 tomcat2 权重为 10 , tomcat1 的 max_fails 为 10 , fail_timeout=120 ;在连接 tomcat1 的 10 次后, nginx 收到 tomcat1 返回 connect refuse 状态, ngxin 判断 tomcat1 为失效,然后重新启动 tomcat1 ,在这段时间内 nginx 判断 tomcat1 还是失效状态,然后将 tomcat2 关闭,然后重启 tomcat2 ,由于所有服务均失效,所以 nginx 将所有服务重新置为有效进行监听,然后将 2 连接均匀分布到了 tomcat1 和 tomcat2 上。
l http 错误状态, nginx 是否记录失效:
nginx 设置 tomcat1 和 tomcat2 权重为 10 , tomcat1 的 max_fails 为 10 , fail_timeout=120 ;配置 proxy_next_upstream 500 、 404 、 502 、 503 、 504 、 timeout 后,当 HTTP 状态为 500 、 502 、 503 、 504(timeout 和 refuse 默认是记录失效的 ) 时, nginx 会判断该次请求为失败记录失败状态,其他所有 HTTP 均不记录失败。