标签:style blog http 使用 os 文件 for 2014
Nginx提供了较多的负载均衡策略,包括加权轮询、IP哈希、fair、一致哈希等。前两个是Nginx官方源码内置的策略,而后面几个都是第三方模块,所以下面我们重点来看前两个内置策略。
Nginx默认采用round_robin加权算法,如果要采用IP哈希策略,那么必须在Nginx的配置文件里通过配置指令ip_hash明确指定。
当整个http配置块被Nginx解析完毕之后,会调用各个http模块对应的初始函数。对于模块ngx_http_upstream_module而言,对应的main配置初始函数是ngx_http_upstream_init_main_conf(),在这个函数中有这样一段代码:
for (i = 0; i < umcf->upstreams.nelts; i++) { init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream: ngx_http_upstream_init_round_robin; if (init(cf, uscfp[i]) != NGX_OK) { return NGX_CONF_ERROR; } }
默认采用加权轮询策略的原因就是在于上述代码中的init赋值一行。如果用户没有做任何策略选择,那么执行的策略初始函数为ngx_http_upstream_init_round_robin,也就是加权轮询策略。否则的话执行的是uscfp[i]->peer.init_upstream指针函数,如果有配置执行ip_hash ,那么就是ngx_http_upstream_init_ip_hash()。
4.down:即主动表示其未宕机状态,不参与被选择。
typedef struct { ngx_addr_t *addrs;//指向存储IP地址的数组的指针,host信息(对应的是 ngx_url_t->addrs ) ngx_uint_t naddrs;//与第一个参数配合使用,数组元素个数(对应的是 ngx_url_t->naddrs ) ngx_uint_t weight; ngx_uint_t max_fails; time_t fail_timeout; unsigned down:1 unsigned backup:1; } ngx_http_upstream_server_t;
这里函数ngx_http_upstream_init_round_robin()所做的工作除了把配置项解析后的结果转存到对应的变量以外,主要还有以下几项:创建后端服务器列表,并且将非后背服务器与后背服务器分开进行各自单独的列表,每一个后段服务器用一个结构体ngx_http_upstream_rr_peer_t对应,列表最前面需要带有一些head信息,所以用ngx_http_upstream_rr_peers_t结构体对应。非后背服务器列表挂载在us->peer.data字段下,而后背服务器列表挂载在非后背服务器列表head于里的next字段下。两个列表的服务器会按初始权重进行排序,高权重的在前面。
在ngx_http_upstream_init_round_robin()中,有如下语句
us->peer.init = ngx_http_upstream_init_round_robin_peer; //回调指针设置
它的调用位置是函数ngx_http_upstream_init_request中,即在针对每个请求选择后端服务器之前被调用。下面对ngx_http_upstream_init_round_robin_peer做了什么做解释,它除了完成初始化工作外,核心是设置回调函数,部分代码如下:
//回调函数设置 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer; r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; r->upstream->peer.tries = rrp->peers->number;
对于只有一台后端服务器的情况,Nginx直接选择它并返回。如果有多台后端服务器,Nginx会循环调用函数ngx_http_uostream_get_peer()按照各台服务器的当前权值进行选择。如果对非后备服务器全部选择失败的话,此时开始尝试选择后备服务器,这同样是对一个服务器列表进行选择,所以处理情况与对非后备服务器处理情况进行选择的逻辑一致。如果对后备服务器选择也失败,那么ngx_http_upstream_get_round_robin_peer返回NGX_BUSY,意味着当前没有后端服务器来处理该请求。
后端服务器权值计算在函数ngx_http_uostream_get_peer()中,这个函数中还有一个变量total,但要理解这个函数的工作原理,先要区分下表示服务的ngx_http_upstream_rr_peer_t结构体中的一下三个成员变量,
ngx_int_t current_weight; ngx_int_t effective_weight; ngx_int_t weight;
for (i = 0; i < us->servers->nelts; i++) { for (j = 0; j < server[i].naddrs; j++) { if (server[i].backup) { continue; } peers->peer[n].weight = server[i].weight; peers->peer[n].effective_weight = server[i].weight; peers->peer[n].current_weight = 0; n++; } } /* backup servers */ for (i = 0; i < us->servers->nelts; i++) { for (j = 0; j < server[i].naddrs; j++) { if (!server[i].backup) { continue; } backup->peer[n].weight = server[i].weight; backup->peer[n].effective_weight = server[i].weight; backup->peer[n].current_weight = 0; n++; } } /* an upstream implicitly defined by proxy_pass, etc. */ for (i = 0; i < u.naddrs; i++) { peers->peer[i].weight = 1; peers->peer[i].effective_weight = 1; peers->peer[i].current_weight = 0; }
下面分析这三个变量在负载均衡过程中的变化:
轮询策略是取current_weight最大的服务器。每次取到后端服务(用best表示)后,都会把该对象peer的current_weight减去total的值。因为该服务刚被选中过,因此要降低权值。
关于effective_weight的变化,有两处,一个是在函数ngx_http_upstream_get_peer中:
//服务正常,effective_weight 逐渐恢复正常 if (peer->effective_weight < peer->weight) { peer->effective_weight++; }
if (peer->max_fails) { //服务发生异常时,调低effective_weight peer->effective_weight -= peer->weight / peer->max_fails; }
权重高的会优先被选中,而且被选中的频率也更高。权重低的也会由于权重逐渐增长获得被选中的机会,如下表所示:
selected server |
current_weight beforeselected |
current_weight afterselected |
a |
{ 5, 1, 2 } |
{ -3, 1, 2 } |
c |
{ 2, 2, 4 } |
{ 2, 2, -4 } |
a |
{ 7, 3, -2 } |
{ -1, 3, -2 } |
a |
{ 4, 4, 0 } |
{ -4, 4, 0 } |
b |
{ 1, 5, 2 } |
{ 1, -3, 2 } |
a |
{ 6, -2, 4 } |
{ -2, -2, 4 } |
c |
{ 3, -1, 6 } |
{ 3, -1, -2 } |
a |
{ 8, 0, 0 } |
{ 0, 0, 0 } |
用IP负载均衡策略时,当一个客户端请求过来时,Nginx将调用ngx_http_upstream_init_ip_hash_peer()做初始化。之所以这样做是因为在多次哈希选择失败后,Nginx会将选择策略退化到加权轮询。这里会设置ngx_http_upstream_get_ip_hash_peer以在便收到请求时调用。同时会转存Ipv4中三个字节,因为后面在具体的哈希计算时只会用到3个字节。
ngx_http_upstream_get_ip_hash_peer在会计算哈希值,并根据哈希值得到被选中的后端服务器,判断其是否可用,如果可用则保存服务器地址,不可用则在上次哈希结果的基础上再哈希。如果哈希选择失败20次以上或质疑一台后端服务器,此时采用轮询策略。
标签:style blog http 使用 os 文件 for 2014
原文地址:http://blog.csdn.net/walkerkalr/article/details/38322997