美文网首页
nginx加权轮训算法

nginx加权轮训算法

作者: 哭泣哭泣帕拉达 | 来源:发表于2020-03-27 17:35 被阅读0次

    nginx加权轮训算法

    nginx upstream负载均衡默认采用轮训方法

    
    http {
    
        upstream tomcats{
    
            server 192.168.25.131:8080;
    
            server 192.168.25.132:8080;
    
            server 192.168.25.133:8080;
    
        }
    
        server {
    
            listen 80;
    
            server_name 192.168.25.130;
    
    
    
            location / {
    
                proxy_pass http://tomcats;
    
            }
    
        }
    
    }
    
    

    这里暂且将三台server服务器叫做a,b,c。浏览器访问192.168.25.130,每三次请求会均匀转发给a,b,c各一次。这是因为每台服务器默认的权重都是1,所以会均分请求。

    现在为server加上权重,如下:

    
    http {
    
        upstream tomcats{
    
            server 192.168.25.131:8080 weight=5;
    
            server 192.168.25.132:8080 weight=2;
    
            server 192.168.25.133:8080 weight=1;
    
        }
    
        server {
    
            listen 80;
    
            server_name 192.168.25.130;
    
    
    
            location / {
    
                proxy_pass http://tomcats;
    
            }
    
        }
    
    }
    
    

    这时再访问192.168.25.130,每8次请求中有5次转发给a,2次转发给b,1次转发给c。但8次请求并不是{a,a,a,a,a,b,b,c}这样转发的,连续的5次请求转发给a,是不均匀的。nginx使用的是平滑的加权轮训,这样装发给a的5次请求不再是连续的。

    先看一下nginx中加权轮训算法实现

    
    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;
    
            }
    
    
    
            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;
    
    }
    
    

    每个后端peer都有三个权重变量

    1. weight

    配置文件中指定的该后端的权重,次值不变

    1. effective_weight

    后端的有效权重,初始值为weight。

    在释放后端时,如果发现和后端的通信过程中发生了错误,就减小effective_weight。

    此后有新的请求过来时,在选取后端的过程中,再逐步增加effective_weight,最终又恢复到weight。

    之所以增加这个字段,是为了当后端发生错误时,降低其权重。

    1. current_weight

    后端目前的权重,一开始为0,之后会动态调整。那么是怎么个动态调整呢?

    每次选取后端时,会遍历集群中所有后端,对于每个后端,让它的current_weight增加它的effective_weight,

    同时累加所有后端的effective_weight,保存为total。

    如果该后端的current_weight是最大的,就选定这个后端,然后把它的current_weight减去total。如果该后端没有被选定,那么current_weight不用减小。

    .

    对于每个请求,遍历集群中的所有可用后端,对于每个后端peer执行:

    peer->current_weight += peer->effecitve_weight。

    同时累加所有peer的effective_weight,保存为total。

    从集群中选出current_weight最大的peer,作为本次选定的后端。

    对于本次选定的后端,执行:peer->current_weight -= total。

    upstream backend { server a weight=5; server b weight=2; server c weight=1; }

    这样8次请求转发顺序是{a,b,a,a,c,a,b,a}

    相关文章

      网友评论

          本文标题:nginx加权轮训算法

          本文链接:https://www.haomeiwen.com/subject/nmkruhtx.html