Nginx官方支持的后端服务负载均衡策略有加权轮询和IP哈希,默认采用加权轮询策略。
加权轮询流程图
代码流程
static ngx_http_upstream_rr_peer_t *
ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
{
time_t now;
uintptr_t m;
ngx_int_t total;
ngx_uint_t i, n, p;
ngx_http_upstream_rr_peer_t *peer, *best;
now = ngx_time();
best = NULL;
total = 0;
#if (NGX_SUPPRESS_WARN)
p = 0;
#endif
for (peer = rrp->peers->peer, i = 0;
peer;
peer = peer->next, i++)
{
n = i / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
if (rrp->tried[n] & m) {
continue;
}
if (peer->down) {
continue;
}
if (peer->max_fails
&& peer->fails >= peer->max_fails
&& now - peer->checked <= peer->fail_timeout)
{
continue;
}
if (peer->max_conns && peer->conns >= peer->max_conns) {
continue;
}
peer->current_weight += peer->effective_weight;
total += peer->effective_weight;
if (peer->effective_weight < peer->weight) {
peer->effective_weight++;
}
if (best == NULL || peer->current_weight > best->current_weight) {
best = peer;
p = i;
}
}
if (best == NULL) {
return NULL;
}
rrp->current = best;
n = p / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
rrp->tried[n] |= m;
best->current_weight -= total;
if (now - best->checked > best->fail_timeout) {
best->checked = now;
}
return best;
}
weight |
始终是初始权重 |
currentWeight |
开始是初始权重,后面会变化 |
effectiveWeight |
开始是初始权重,节点异常后-1,遍历选择时<初始权重后+1 |
1. 所有节点的effectiveWeight之和作为totalWeight
2. 遍历所有节点,currentWeight += effectiveWeight,effectiveWeight<初始权重后+1
3. currentWeight值最大的节点作为选中节点
4. 选中节点currentWeight -= totalWeight
3个节点正常,权重分别为4、2、1。
经过7次加权轮询后,serverA、serverB、serverC的权重又变回了4、2、1。
参考资料
《深入剖析Nginx》
Nginx负载均衡算法--加权轮询(golang 实现)