解读nginx 轮询、加权轮询算法的源码尽可能详细
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函数,来选择一个节点,该函数会根据节点的权重值,来选择下一个节点。如果下一个节点权重值较高,则选择该节点,并更新当前节点的权重值;否则,继续循环,直到找到一个权重值较高的节点。
需要注意的是,加权轮询算法中,每个节点的权重值应该是一个整数。如果需要使用小数,可以将小数转换为整数后使用
原文地址: https://www.cveoy.top/t/topic/fTID 著作权归作者所有。请勿转载和采集!