Nginx负载均衡策略

Nginx支持六种负载均衡策略,其中开源版的Nginx支持四种,Nginx Plus支持两种:

  1. Round Robin

所有请求将被分布发放给后端的所有服务器,在发布请求时还会考虑每台服务器设置的权重。该策略为默认策略,不需要额外的设置:

下例中,请求被分配给后端backend1和backend2两台服务器,两台服务器的权重未设置的话则表示权重都为1。

upstream backend {
   # no load balancing method is specified for Round Robin
   server backend1.example.com;
   server backend2.example.com;
} 

同时可以设置weight这个参数来设置服务器的权重,用于当后端服务器的性能不均时为性能更好的服务器设置高权重,以便高性能服务器能处理更多的请求。下例中,backend1的权重设置为3,backend2权重未做设置,则未默认值1:

upstream backend {
   server backend1.example.com weight=3;
   server backend2.example.com;
} 
  1. Least Connection

当有请求过来时,Nginx会将请求发送给后端连接数最少的服务器,同时也会考虑后端服务器的权重值:

upstream backend {
    least_conn;
    server backend1.example.com;
    server backend2.example.com;
} 
  1. IP Hash

每个请求按照访问的IP地址的hash结果分配服务器,这样每个访客会访问固定的后端服务器,可以解决会话保持的问题:

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
} 

如果后端的某台服务器需要临时从负载均衡组里移除出来,可以在配置文件中将该服务器标注为down,用以保存客户端IP的hash。原本应该发送给该服务器的请求会自动的转发给下一台服务器:

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
} 
  1. Generic Hash

按照用户指定的键值,例如文本字符串、变量或者这些的组合,做hash再决定请求分发给后端的哪台服务器。例如这个用户指定的键值可以是一对IP地址和端口,或者是URI。

upstream backend {
    hash $request_uri consistent;
    server backend1.example.com;
    server backend2.example.com;
} 

如果指定了consistent参数,则使用一致性哈希算法。该方法可以确保在向组中添加或者删除服务器时,只有少数键值重新映射到不同的服务器,这有助于为高速缓存服务器实现更好的高速缓存命中率。

  1. Least Time(Nginx Plus Only)

Nginx Plus选择平均时延最低且连接数最少的后端服务器处理每个请求。least_time参数提供了如下变量用于计算最低时延:

  • header – 从服务器获取第一个字节所用的时间
  • last_byte – 从服务器获取全部相应的时间
  • last_byte inflight – 从服务器获取全部相应的时间,包括未完成的请求
upstream backend {
    least_time header;
    server backend1.example.com;
    server backend2.example.com;
} 
  1. Random

对于每个请求,Nginx将会随机的发送给后端的服务器。如果使用了two这个参数,则Nginx会随机的选择两台服务器,并使用如下规则从这两台中选出一台用于处理请求:

  • least_conn – 活动连接数最少的服务器
  • least_time=header (Nginx Plus) – 接收响应header平均用时最少的服务器($upstream_header_time)
  • least_time=last_byte (Nginx Plus) – 接收全部响应平均用时最少的服务器($upstream_response_time)
upstream backend {
    random two least_time=last_byte;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
    server backend4.example.com;
} 

一般在分布式环境里面,如果使用多个负载均衡器将请求分发给后端,我们可以使用Random策略。如果使用一个负载均衡处理所有的请求,请使用其他的策略,例如round robin,least connection或者least time。

接下来我们做个测试,验证一下Round Robin中的权重。

首先,我们需要一台Linux服务器,我这里使用一台Ubuntu 18.04。前端一台Nginx做负载均衡,后端使用三台Nginx做为web server。四台Nginx服务器均运行在容器中,其中前端负载均衡Nginx映射主机的8080端口供外部访问,三台后端Nginx服务器不映射主机端口,直供前端负载均衡Nginx容器内部访问。

  1. 服务器安装docker:
apt-get install docker.io
  1. docker建议一个桥接的网络,用于所有容器之间的通信:
docker network create nginx_network
  1. 使用桥接网络创建四个nginx容器,其中一个作为前端的负载均衡,三个作为后端的web server:
docker run --name nginx_frontend -d --network nginx_network -p 8080:80 nginx
docker run --name nginx_backend1 -d --network nginx_network nginx
docker run --name nginx_backend2 -d --network nginx_network nginx
docker run --name nginx_backend3 -d --network nginx_network nginx
  1. 将nginx_frontend容器的/etc/nginx/nginx.conf文件从容器中拷贝出来:
docker cp nginx_frontend:/etc/nginx/nginx.conf .
  1. 编辑拷贝出来的nginx配置文件,配置如下:
 http {    
     upstream backend {
         server nginx_backend1 weight=1;
         server nginx_backend2 weight=3;
         server nginx_backend3 weight=6;
     }
     server {
         listen 8080;
         location / {
             proxy_pass http://backend;
         }
     }   
 }

由于我们所有的四个容器都创建在nginx_network上,所以四个容器之间可以通过容器名名进行通信,配置文件里面server后面直接写容器名是没问题的。

  1. 修改每台Web Server的index.html文件用于区分:
docker exec -it nginx_backend1 /bin/bash
echo "This is nginx_backend1" > /usr/share/nginx/html/index.html
exit
docker exec -it nginx_backend2 /bin/bash
echo "This is nginx_backend2" > /usr/share/nginx/html/index.html
exit
docker exec -it nginx_backend3 /bin/bash
echo "This is nginx_backend3" > /usr/share/nginx/html/index.html
exit
  1. 重启前端做负载均衡的nginx_frontend容器,使修改的配置文件生效:
nginx -s reload
  1. 使用脚本验证权重设置是否生效:
for i in $(seq 1 100)
do 
curl -L http://localhost:8080 >> curl_output
sleep 1
done
cat curl_output |grep nginx_backend1|wc –l
cat curl_output |grep nginx_backend2|wc –l
cat curl_output |grep nginx_backend3|wc -l 

此条目发表在docker分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注