Nginx支持六种负载均衡策略,其中开源版的Nginx支持四种,Nginx Plus支持两种:
- 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; }
- Least Connection
当有请求过来时,Nginx会将请求发送给后端连接数最少的服务器,同时也会考虑后端服务器的权重值:
upstream backend { least_conn; server backend1.example.com; server backend2.example.com; }
- 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; }
- Generic Hash
按照用户指定的键值,例如文本字符串、变量或者这些的组合,做hash再决定请求分发给后端的哪台服务器。例如这个用户指定的键值可以是一对IP地址和端口,或者是URI。
upstream backend { hash $request_uri consistent; server backend1.example.com; server backend2.example.com; }
如果指定了consistent参数,则使用一致性哈希算法。该方法可以确保在向组中添加或者删除服务器时,只有少数键值重新映射到不同的服务器,这有助于为高速缓存服务器实现更好的高速缓存命中率。
- 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; }
- 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容器内部访问。
- 服务器安装docker:
apt-get install docker.io
- docker建议一个桥接的网络,用于所有容器之间的通信:
docker network create nginx_network
- 使用桥接网络创建四个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
- 将nginx_frontend容器的/etc/nginx/nginx.conf文件从容器中拷贝出来:
docker cp nginx_frontend:/etc/nginx/nginx.conf .
- 编辑拷贝出来的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后面直接写容器名是没问题的。
- 修改每台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
- 重启前端做负载均衡的nginx_frontend容器,使修改的配置文件生效:
nginx -s reload
- 使用脚本验证权重设置是否生效:
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