Nginx负载均衡策略

TrumanWong
6/24/2024
TrumanWong

负载均衡技术是将大量的客户端请求通过特定的策略分配到集群中的节点,实现快速响应的应用技术。在应对高并发的应用请求时,单节点的应用服务计算能力有限,无法满足客户端的响应需求,通过负载均衡技术,可以将请求分配到集群中的多个节点中,让多个节点分担高并发请求的运算,快速完成客户端的请求响应。

Nginx支持多种负载均衡策略,如轮询Round Robin、一致性哈希Consistent Hash、IP哈希IP Hash、最少连接least_conn等。Nginx的默认负载均衡策略为轮询策略,不需要配置指令,轮询策略通过server的权重参数可实现手动分配的加权轮询策略。负载均衡策略配置指令均应编辑在upstream指令域的最上方。

Nginx负载均衡示例配置:

upstream backend {
    server backend1.example.com       weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

server语法:server address [parameters]

address可以指定为域名,也可以使用ip地址+端口形式,如果不指定端口,则默认使用80端口,或者使用unix套接字路径。

server指定可以定义以下参数:

轮询

轮询Round Robin策略是Nginx配置中默认的负载均衡策略,该策略将客户端的请求依次分配给后端的服务器节点,对后端集群中的服务器实现轮流分配。轮询策略绝对均衡,且实现简单,但也会因后端服务器处理能力的不同而影响整个集群的处理性能。

加权轮询

Nginx的轮询策略中,为了避免因集群中服务器性能的差异对整个集群性能造成影响,在轮询策略的基础上增加了权重参数,让使用者可以手动根据集群中各服务器的性能将请求数量按照权重比例分配给不同的被代理服务器。

平滑轮询

在加权轮询策略中,会按照权重的高低分配客户端请求,若按照高权重分配完再进行低权重分配的话,可能会出现的情况是高权重的服务器一直处于繁忙状态,压力相对集中。Nginx通过平滑轮询算法,使得上游服务器组中的每台服务器在总权重比例分配不变的情况下,均能参与客户端请求的处理,有效避免了在一段时间内集中将请求都分配给高权重服务器的情况发生。

示例如下:

http {
    upstream backend {
        server backend1.example.com weight=5;
        server backend2.example.com weight=1;
        server backend3.example.com weight=1;
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://backend;
        }
    }
}

配置样例中Nginx平滑轮询策略计算过程如下:

一致性哈希

配置语法:hash key [consistent]

Nginx启用哈希的负载均衡策略,是用hash指令来设置的。哈希策略方法可以针对客户端访问的URL计算哈希值,对相同的URL请求,Nginx可以因相同的哈希值而将其分配到同一后端服务器。当后端服务器为缓存服务器时,将极大提高命中率,提升访问速度。

优点

可以使不同客户端的相似请求发送给同一被代理服务器,当被代理服务器为缓存服务器场景应用时,可以极大提高缓存的命中率。

缺点

当上游服务器组中的节点数量发生变化时,将导致所有绑定被代理服务器的哈希值重新计算,影响整个集群的绑定关系,产生大量回源请求。

针对哈希算法的缺点,Nginx提供了consistent参数启用一致性哈希Consistent Hash负载均衡策略。Nginx采用的是Ketama一致性哈希算法,使用一致性哈希策略后,当上游服务器组中的服务器数量变化时,只会影响少部分客户端的请求,不会产生大量回源。

Nginx一致性哈希计算过程如下:

配置示例如下:

http {
    upstream backend {
        hash $request_uri consistent;
        server backend1.example.com weight=5;
        server backend2.example.com weight=1;
        server backend3.example.com weight=1;
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://backend;
        }
    }
}

计算过程如下:

IP哈希

IP哈希IP Hash负载均衡策略根据客户端IP计算出哈希值,然后把请求分配给该数值对应的被代理服务器。在哈希值不变且被代理服务器可用的前提下,同一客户端的请求始终会被分配到同一台被代理服务器上。IP哈希负载均衡策略常被应用在会话Session保持的场景。

HTTP客户端在与服务端交互时,因为HTTP协议是无状态的,所以任何需要上下文逻辑的情景都必须使用会话保持机制,会话保持机制是通过客户端存储由唯一的Session ID进行标识的会话信息,每次与服务器交互时都会将会话信息提交给服务端,服务端依照会话信息实现客户端请求上下文的逻辑关联。会话信息通常存储在被代理服务器的内存中,如果负载均衡将客户端的会话请求分配给其他被代理服务器,则该会话逻辑将因为会话信息失效而中断。所以为确保会话不中断,需要负载均衡将同一客户端的会话请求始终都发送到同一台被代理服务器,通过会话保持实现会话信息的有效传递。

配置示例如下:

http {
    upstream backend {
        ip_hash;
        server backend1.example.com weight=5;
        server backend2.example.com weight=1;
        server backend3.example.com weight=1;
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://backend;
        }
    }
}

计算过程如下:

最少连接

默认配置下轮询算法是把客户端的请求平均分配给每个被代理服务器,每个被代理服务器的负载大致相同,该场景有个前提就是每个被代理服务器的请求处理能力是相当的。如果集群中某个服务器处理请求的时间比较长,那么该服务器的负载也相对增高。在最少连接least_conn负载均衡策略下,会在上游服务器组中各服务器权重的前提下将客户端请求分配给活跃连接最少的被代理服务器,进而有效提高处理性能高的被代理服务器的使用率。

http {
    upstream backend {
        least_conn;
        server backend1.example.com weight=4;
        server backend2.example.com weight=2;
        server backend3.example.com weight=1;
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://backend;
        }
    }
}

计算过程如下:

随机负载算法

语法:random [two [method]];

Nginx集群环境下,每个Nginx均通过自身对上游服务器的了解情况进行负载均衡处理,这种场景下,很容易出现多台Nginx同时把请求都分配给同一台被代理服务器的场景,该场景被称为羊群行为Herd BehaviorNginx基于两种选择的力量Power of Two Choices原理,设计了随机Random负载算法。该算法使Nginx不再基于片面的情况了解使用固有的负载均衡策略进行被代理服务器的选择,而是随机选择两个,在经过比较后进行最终的选择。随机负载算法提供了一个参数two,当这个参数被指定时,Nginx会在考虑权重的前提下,随机选择两台服务器,然后用以下几种方法选择一个服务器:

配置示例如下:

http {
    upstream backend {
        random two least_conn;
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com;
        server backend4.example.com;
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://backend;
        }
    }
}

在只有单台Nginx服务器时,一般不建议使用随机负载算法。