Nginx是一个高性能的Web服务器和反向代理服务器,支持轮询和加权轮询算法用于负载均衡。在Nginx中,轮询算法是默认的负载均衡算法,而加权轮询算法则需要手动配置。

首先,我们来看一下Nginx的轮询算法的实现。在Nginx的源码中,轮询算法的核心代码实现在ngx_http_upstream_round_robin.c文件中。该文件定义了ngx_http_upstream_round_robin_peer_data_t结构体,该结构体包含了轮询算法中需要用到的一些参数,如服务器列表、当前轮询位置等。下面是该结构体的定义:

typedef struct {
    ngx_uint_t                      current; // 当前轮询位置
    ngx_uint_t                      tries;   // 当前尝试次数
    ngx_http_upstream_rr_peer_t    *peer;    // 当前服务器节点
} ngx_http_upstream_round_robin_peer_data_t;

在轮询算法中,每个请求都会依次分配给服务器列表中的节点,直到所有节点都被分配过一次。然后,从头开始重新分配。因此,我们需要一个变量来记录当前轮询的位置。在Nginx中,这个变量被定义为ngx_uint_t current。

在每次请求中,Nginx会从服务器列表中选择一个节点,并将其信息存储在ngx_http_upstream_round_robin_peer_data_t结构体中。在这个结构体中,peer字段指向了当前被选中的服务器节点。tries字段用于记录当前请求尝试的次数。

下面是轮询算法的核心代码实现:

static ngx_int_t
ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
{
    ngx_http_upstream_rr_peer_data_t  *rrp = data;

    ngx_uint_t                        i, n;
    ngx_http_upstream_rr_peer_t      *peer;

    if (rrp->peers->single) {
        peer = rrp->peers->peer;

        if (peer->down) {
            return NGX_BUSY;
        }

        rrp->current = 0;
        rrp->peer = peer;

        return NGX_OK;
    }

    n = rrp->peers->number;

    if (n == 1) {
        peer = rrp->peers->peer;

        if (peer->down) {
            return NGX_BUSY;
        }

        rrp->peer = peer;

        return NGX_OK;
    }

    for ( ;; ) {
        peer = &rrp->peers->peer[rrp->current];

        if (!peer->down) {
            rrp->peer = peer;

            return NGX_OK;
        }

        if (++rrp->current >= n) {
            rrp->current = 0;
        }

        if (++rrp->tries > n) {
            return NGX_BUSY;
        }
    }
}

在这段代码中,我们首先判断服务器列表中是否只有一个节点,如果是,则直接选择该节点。否则,我们通过循环遍历服务器列表,直到找到一个未被标记为down的节点。如果没有找到未被标记为down的节点,则重置轮询位置,并返回NGX_BUSY,表示所有节点都已经down。

接下来,我们来看一下Nginx加权轮询算法的实现。加权轮询算法和轮询算法的区别在于,它会根据服务器节点的权重值,来分配更多的请求给权重值较高的节点。在Nginx中,加权轮询算法的实现和轮询算法类似,只是在选择节点时,需要考虑节点的权重值。

加权轮询算法的实现代码如下:

static ngx_int_t
ngx_http_upstream_get_round_robin2_peer(ngx_peer_connection_t *pc, void *data)
{
    ngx_http_upstream_rr_peer_data_t  *rrp = data;

    ngx_uint_t                        i, n, p;
    ngx_http_upstream_rr_peer_t      *peer;

    if (rrp->peers->single) {
        peer = rrp->peers->peer;

        if (peer->down) {
            return NGX_BUSY;
        }

        rrp->current = 0;
        rrp->peer = peer;

        return NGX_OK;
    }

    n = rrp->peers->number;

    if (n == 1) {
        peer = rrp->peers->peer;

        if (peer->down) {
            return NGX_BUSY;
        }

        rrp->peer = peer;

        return NGX_OK;
    }

    p = ngx_http_upstream_peek_peer(rrp->peers);

    if (p == NGX_ERROR) {
        return NGX_BUSY;
    }

    if (p != rrp->current) {
        rrp->current = p;
        rrp->tries = 0;
    }

    for (i = 0; i < n; i++) {
        peer = &rrp->peers->peer[rrp->current];

        if (!peer->down) {
            if (peer->weight >= rrp->current_weight) {
                rrp->current_weight += peer->weight;
                rrp->peer = peer;

                return NGX_OK;
            }

            rrp->current_weight -= peer->weight;
        }

        if (++rrp->current >= n) {
            rrp->current = 0;
            rrp->tries++;
        }

        if (rrp->tries > n) {
            return NGX_BUSY;
        }
    }

    return NGX_BUSY;
}

在这段代码中,我们首先判断服务器列表中是否只有一个节点,如果是,则直接选择该节点。否则,我们通过ngx_http_upstream_peek_peer函数,来选择一个节点,该函数会根据节点的权重值,来选择下一个节点。如果下一个节点权重值较高,则选择该节点,并更新当前节点的权重值;否则,继续循环,直到找到一个权重值较高的节点。

需要注意的是,加权轮询算法中,每个节点的权重值应该是一个整数。如果需要使用小数,可以将小数转换为整数后使用

解读nginx 轮询、加权轮询算法的源码尽可能详细

原文地址: https://www.cveoy.top/t/topic/fTID 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录