# nginx负载均衡实战分享

> 作者/来源: UCloud 运营管理员
> 发布时间: 2023-01-11T05:20:00.000Z
> 分类: 云主机
> 标签: AI, Java, 前端
> 原文链接: http://117.50.162.249:3000/yun/articles/678

---

# nginx负载均衡实战分享

> 来源: https://www.ucloud.cn/yun/130213.html
> 作者: IT那活儿
> 发布日期: 发布于2023-01-11 13:20

nginx负载均衡实战分享

负载均衡的介绍

负载均衡是由多台服务器以对称方式组成服务器集群，每台服务器都具等价关系，均可多带带对外提供服务且无需其他服务器辅助。通过对应负载分担均衡，将外部发送请求按既定规则分发到对称集群架构其中一台服务器上，对应接收请求服务器也独立地回应客户端请求。均衡负载能够平均分配客户请求到服务器阵列，以快速获取数据，解决大并发访问服务的洪峰问题。此种集群技术可用最少的投入获得超高的性能，是一种性价比较高的并发解决方案之一。

负载均衡建立在网络层之上，提供了一种廉价有效透明的方法扩展网络设备和服务器带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

负载均衡（LoadBalance）其原意就是前端请求分摊到多个操作单元进行取数执行操作，例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等，从而共同完成工作任务。

常用负载均衡方法

一、用户手动选择

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_000.png)

这是一种比较古老的方式，目主要通过提供不同的线路、不同服务器链接的方式，来实现负载均衡。

这种方式在一些提供下载、在线影院、直播等网站比较常见。

优点：

- 1、部署简单，新增服务器或链路只需增加对应的入口即可
- 2、维护方便，如果有服务器宕机只需关闭对应入口即可

缺点：

- 1、智能化程度不高，需用户手动切换
- 2、分配不可控，容易出现服务器访问量极不平衡等情况

二、DNS轮询

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_001.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_002.png)

大多域名注册商都支持多条A记录的解析，这就是DNS轮询，DNS服务器将解析请求按照A记录的顺序，逐一分配到不同的IP上，这样就完成了简单的负载均衡。

优点：

- 1、基本上无成本，因为往往域名注册商的这种解析都是免费的；
- 2、部署方便，除了网络拓扑的简单扩增，新增的Web服务器只要增加一个公网IP即可。

缺点：

- 1、健康检查，如果某台服务器宕机，DNS服务器是无法知晓的，仍旧会将访问分配到此服务器。修改DNS记录全部生效起码要3-4小时，甚至更久；
- 2、分配不均，如果几台Web服务器之间的配置不同，能够承受的压力也就不同，但是DNS解析分配的访问却是均匀分配的。其实DNS也是有分配算法的，可以根据当前连接较少的分配、可以设置Rate权重分配等等，只是目前绝大多数的DNS服务器都不支持；

三、四/七层负载均衡

现代负载均衡技术通常操作于OSI网络模型的第四层或第七层。第四层负载均衡将一个Internet上合法注册的IP地址映射为多个内部服务器的IP地址，对每次TCP连接请求动态使用其中一个内部IP第，达到负载均衡的目的。在第四层交换机中，此中均衡技术得到广泛的应用，一个目标地址是服务器群VIP连接请求的数据包流经交换机，交换机根据源端和目的IP地址、TCP或者UDP端口号和一定的负载策略，在服务器IP和VIP间进行映射，选取服务器群众最好的服务器来处理连接请求。

第七层负载均衡控制应用层服务的内容，提供一种对访问流量的高层控制方式，适合对HTTP服务器群的应用。第七层负载均衡技术通过检查流经的HTTP报头，根据报头内的信息来执行负载均衡任务。

常见四/七层负载均衡设备

- 硬件负载均衡交换机，代表有F5、array等。
- 软件负载均衡器，Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件。

软件四/七层负载均衡

1.软件四层负载均衡

代表作为LVS，LVS是一个开源的软件，可以实现linux平台下的简单负载均衡。lvs集群采用IP负载均衡技术和基于内容请求分发技术。调度器具有很好的吞吐率，将请求均衡的转移到不同的服务器上执行，且调度器自动屏蔽掉服务器的故障，从而将一组服务器构成一个高性能的、高可用的虚拟服务器。整个服务器集群的结构对客户是透明的，而且无需修改客户端和服务器端的程序。

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_003.png)

LVS通过修改数据包Ip地址，Mac地址实现负载均衡。

LVS由ipvs(内核中),ipvsadm(用户态)组成。LVS需要理解tcp，ip头部。

当tcp握手信号，SYN数据包达到时，ipvs选择一个后端服务器，将数据包进行转发。在此之后，所有包含相同的ip，tcp头部的数据包都会被转发到之前选择的服务器上。很明显，ipvs无法感知数据包内容。

2.软件的七层负载均衡

大多HTTP反向代理方式，代表产品有nginx、haproxy等，nginx的反向代理负载均衡能够很好的支持虚拟主机，可配置性很强，可以按轮询、IP哈希、URL哈希、权重等多种放肆对后端服务器做负载均衡，同时还支持后端服务器的健康检查。

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_004.png)

nginx负载均衡工作在7层，它会与client、upstream分别建立tcp连接，nginx需要维护这两个连接的状态。

nginx的stream模块可以用于4层负载均衡，主要用于tcp、udp的负载均衡。

nginx负载均衡算法

1.weight权重轮循

在轮循算法的基础上加上权重，即为权重轮循算法，当使用该算法时，权重和用户访问成正比，权重值越大，被转发的请求也就越多。可以根据服务器的配置和性能指定权重值大小，有效解决新旧服务器性能不均带来的请求分配问题。

upstream myapp1 {

server 172.1.1.103 weight=1;

server 172.1.1.104 weight=2;

}

### 

2.ip\_hash

每个请求按客户端IP 的 hash结果分配，当新的请求到达时，先将其客户端IP通过哈希算法哈希出一个值，在随后的客户端请求中，客户IP 的哈希值只要相同，就会被分配至同一台服务器，该调度算法可以解决动态网页的session 共享问题，但有时会导致请求分配不均，即无法保证1:1 的负载均衡，因为在国内大多数公司都是NAT 上网模式，多个客户端会对应一个外部IP，所以，这些客户端都会被分配到同一节点服务器，从而导致请求分配不均。LVS负载均衡的 -P参数、keepalived配置里的persistence\_timeout 50 参数都类似这个Nginx 里的ip\_hash 参数，其功能均为解决动态网页的session 共享问题。注意：当负载调度算法为ip\_hash时，后端服务器在负载均衡调度中的状态不能有weight 和backup ，即使有也不会生效。

upstream myapp1 {

ip\_hash;

server 172.1.1.103;

server 172.1.1.104;

}

### 

3.轮询

按客户端请求顺序把客户端的请求逐一分配到不同的后端节点服务器，如果后端节点服务器宕机（默认情况下nginx只检测80端口）。宕机的服务器会自动从节点服务器池中剔除，以便客户端的用户访问不受影响。新的请求会分配给正产的服务器。

upstream myapp1 {

server 172.1.1.103;

server 172.1.1.104;

}

### 

4.fair

调度算法会根据后端节点服务器的响应时间来分配请求，响应时间短的优先分配。这是更加智能的调度算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡，也就是根据后端服务器的响应时间来分配请求，响应时间短的优先分配。Nginx本身是不支持 fair调度算法的，如果需要使用这种调度算法，必须下载Nginx 的相关模块upstream\_fair。

upstream myapp1 {

fair;

server 172.1.1.103;

server 172.1.1.104;

}

### 

5.url\_hash

按访问URL 的 hash结果来分配请求，使每个URL定向到同一个后端服务器，可以进一步提高后端缓存服务器的效率命中率。（多用于后端服务器为缓存时的场景下）Nginx本身是不支持rul\_hash的，如果需要使用这种调度算法，必须安装Nginx 的hash模块软件包。

upstream myapp1 {

server 172.1.1.103;

server 172.1.1.104;

hash $request\_uri;

hash\_method crc32;

}

### 

6.Nginx负载均衡调度状态

在Nginxupstream模块中，可以设定每台后端服务器在负载均衡调度中的状态，常用的状态有：

- 1、down，表示当前的server暂时不参与负载均衡
- 2、backup，预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候，才会请求backup机器，因此这台机器的访问压力最低
- 3、max\_fails，允许请求失败的次数，默认为1，当超过最大次数时，返回proxy\_next\_upstream模块定义的错误。
- 4、fail\_timeout，请求失败超时时间，在经历了max\_fails次失败后，暂停服务的时间。max\_fails和fail\_timeout可以一起使用。

nginx负载均衡运用场景

1.HTTP负载均衡

upstream模块控制HTTP的负载均衡。这个模块定义了一个目的池，这个目的池可以用IP地址和DNS记录，或者混合使用。

upstream模块模块还定义了任何单个请求是如何分配给任何上游服务器。

在下边的例子中，srv1不参与负载，srv2只有在其他服务器宕机或忙时才参与负载，srv3、srv4参与负载，其中每六次srv3访问五次，srv4一次。所有的请求被代理到服务组node，然后nginx负载均衡的分发请求。

nginx反向代理实现包括下面这些负载均衡HTTP、HTTPS、FastCGI、uwsgi，SCGI和memcached。

要配置HTTPS的负载均衡，只需使用“https”开头的协议。

当要设置FastCGI，uwsgi，SCGI，或者memcached的负载平衡，分别使用fastcgi\_pass，uwsgi\_pass，scgi\_pass和memcached\_pass指令。

upstream node {

server 192.9.191.31:8001 down;

server 192.9.191.31:8002 backup;

server www.aa.com:8003 weight=5;

server 192.9.191.31:8004 max\_fail=1 fail\_timeout=10s;

}

server{

listen 80;

server\_name www.test.com test.com;

location / {

proxy\_pass http://node;

}

}

2.TCP、UDP负载均衡

Nginx使用了一个新的stream模块来实现TCP负载均衡，这个模块，类似于http和mail模块，允许我们配置一组监听TCP连接的服务。允许你配置多个服务的TCP连接，通过在upstream的server组中配置proxy\_pass指令。

TCP负载均衡支持Nginx原有的调度算法，包括轮询调度，哈希（选择一致）等。同时，调度信息数据也会和健壮性检测模块一起协作，为每个连接选择适当的目标上游服务器。

和其他upstream模块一样，TCP的stream模块也支持自定义负载均和的转发权重（配置weight），还有backup和down的参数，用于踢掉失效的上游服务器。max\_conns参数可以限制一台服务器的TCP连接数量，根据服务器的容量来设置恰当的配置数值，尤其在高并发的场景下，可以达到过载保护的目的。

stream{

upstream mysql\_read {

server read1.example.com:3306 weight=5;

server read2.example.com:3306;

server 10.10.12.34:3306 backup;

}

server {

listen 3306;

proxy\_pass mysql\_read;

}

}

案例分享

案例一

后端3台tomcat服务器以2主一备的形式通过2台nginx服务器实现负载均衡，同时nginx通过keepalived实现主备配置

### **1、地址分配**

nginx:172.1.1.106、172.1.1.107

VIP地址:172.1.1.108

tomcatIP:172.1.1.102、172.1.1.103、172.1.1.105

### 

### **2、应用部署及配置**

1. #### 环境配置及tomcat安装:

安装java环境:

chmod +x jdk-6u16-linux-i586.bin  

./jdk-6u16-linux-i586.bin  

ln -s /usr/local/jdk-1.6.0-16/bin/java /usr/bin/java  

ln -s /usr/local/jdk-1.6.0-16/bin/javac /usr/bin/javac  

ln -s /usr/local/jdk-1.6.0-16 /usr/local/jdk  

ln -s /usr/local/jdk-1.6.0-16/jre /usr/local/jre  

tar zxvf apache-tomcat-6.0.20.tar.gz  

mv apache-tomcat-6.0.20 /usr/local/tomcat

设置环境变量:

JAVA\_HOME=/usr/local/jdk  

export JAVA\_HOME  

JRE\_HOME=/usr/local/jre  

export JRE\_HOME  

CLASSPATH=/usr/local/tomcat/common/lib/:/usr/local/jdk/lib:/usr/local/jre/lib  

export CLASSPATH  

PATH=$PATH:/usr/local/tomcat/bin/:/usr/local/apache/bin:/usr/local/jdk/bin:/usr/local/jre/bin  

export PATH  

TOMCAT\_HOME=/usr/local/tomcat  

export TOMCAT\_HOME

2. #### nginx安装及配置

下载及安装nginx:

wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.7.tar.gz  

tar zxvf pcre-7.7.tar.gz  

cd pcre-7.7/  

./configure  

make && make install  

wget http://sysoev.ru/nginx/nginx-0.7.17.tar.gz  

tar zxvf nginx-0.7.17.tar.gz  

cd nginx-0.7.17/  

./configure --prefix=/usr/local/nginx 

make && make install

nginx.conf配置文件,两台nginx服务器保持一致

user nobody nobody;  

worker\_processes 1;  

pid /usr/local/nginx/logs/nginx.pid;  

worker\_rlimit\_nofile 51200;  

events  

{  

use epoll;  

worker\_connections 51200;  

}  

http{  

include       mime.types;  

default\_type application/octet-stream;  

server\_names\_hash\_bucket\_size 128;  

client\_header\_buffer\_size 32k;  

large\_client\_header\_buffers 4 32k;  

client\_max\_body\_size 8m;  

sendfile on;  

tcp\_nopush     on;  

keepalive\_timeout 60;  

tcp\_nodelay on;  

fastcgi\_connect\_timeout 300;  

fastcgi\_send\_timeout 300;  

fastcgi\_read\_timeout 300;  

fastcgi\_buffer\_size 64k;  

fastcgi\_buffers 4 64k;  

fastcgi\_busy\_buffers\_size 128k;  

fastcgi\_temp\_file\_write\_size 128k;  

gzip on;  

gzip\_min\_length 1k;  

gzip\_buffers     4 16k;  

gzip\_http\_version 1.0;  

gzip\_comp\_level 2;  

gzip\_types       text/plain application/x-javascript text/css application/xml;  

gzip\_vary on;  

upstream node

{  

server 172.1.1.102:8080;  

server 172.1.1.103:8080;  

server 172.1.1.105:8080 backup;  

}  

server {  

listen 80;  

server\_name test.com;  

location / {  

root /var/www ;  

index index.jsp index.htm index.html;  

proxy\_redirect off;  

proxy\_set\_header Host $host;  

proxy\_set\_header X-Real-IP $remote\_addr;  

proxy\_set\_header X-Forwarded-For $proxy\_add\_x\_forwarded\_for;  

proxy\_pass http://node;  

}  

log\_format access $remote\_addr - $remote\_user [$time\_local] "$request"  

$status $body\_bytes\_sent "$http\_referer"  

"$http\_user\_agent" $http\_x\_forwarded\_for;  

access\_log /var/log/access.log access;  

}  

}

3. #### Nginx服务器双机部署

Keepalived下载安装：

wget http://www.keepalived.org/software/keepalived-1.1.15.tar.gz  

http://www.keepalived.org/software/keepalived-1.2.13.tar.gz

tar zxvf keepalived-1.1.15.tar.gz  

cd keepalived-1.1.15  

./configure  

make  

make install  

cp /usr/local/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/  

cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/  

mkdir /etc/keepalived  

cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/  

cp /usr/local/sbin/keepalived /usr/sbin/  

service keepalived start|stop

两台nginx服务器上keepalived配置文件

172.1.1.106主机：

ip avrrp\_instance VI\_INET1 {  

        state MASTER  

        interface eth0  

        virtual\_router\_id 53  

        priority 200  

        advert\_int 1  

        authentication {  

                auth\_type pass  

                auth\_pass yourpass  

        }  

        virtual\_ipaddress {  

                172.1.1.108  

        }  

}

172.1.1.107主机：

vrrp\_instance VI\_INET1 {  

        state BACKUP  

        interface eth0  

        virtual\_router\_id 53  

        priority 100  

        advert\_int 1  

        authentication {  

                auth\_type pass  

                auth\_pass yourpass  

        }  

        virtual\_ipaddress {  

                172.1.1.108  

        }  

}

以上步骤即可完成nginx主备下的负载均衡配置，具体负载策略大家可以根据现场环境实际情况进行调整，配置仅供参考。

## 

案例二

在流量陡增的互联网面前，接口限流也是很有必要的，尤其是针对高并发的场景。Nginx的限流主要是两种方式：限制访问频率和限制并发连接数。该案例就是一个通过限制单个IP并发连接数防止后端服务器过载的例子。

1. 维护人员接到告警发现tuxedo中间件多个服务出现堵塞，尝试扩服务或重启均无法解决。

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_005.png)

2. 对比业务量情况，发现同比环比均超30%以上

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_006.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/130213/images/130213_007.png)

3. 随即调整nginx限流策略，配置及注释如下

http {

   include      mime.types;

   default\_type application/octet-stream;

   proxy\_intercept\_errors on;

   #log\_format main  $remote\_addr - $remote\_user [$time\_local] "$request"

   #                 $status $body\_bytes\_sent "$http\_referer"

   #                 "$http\_user\_agent" "$http\_x\_forwarded\_for";

   #access\_log logs/access.log  main;

   log\_format main  $remote\_addr - $remote\_user [$time\_local] "$request"

                     $status $body\_bytes\_sent "$http\_referer"

                     "$http\_user\_agent" "$http\_x\_forwarded\_for";

   log\_format acc "$remote\_addr $remote\_user [$time\_local] $request\_method $uri $args $server\_protocol"

                  " $status $body\_bytes\_sent $request\_time $http\_referer $upstream\_addr $upstream\_cache\_status"

                  " $upstream\_status $http\_x\_forwarded\_for $cookie\_route $http\_host $http\_user\_agent <<$request\_body>> <<$resp\_body>> ";

   access\_log logs/access\_acc$hostname$year$month$day.log acc ;

   sendfile       on;

   tcp\_nopush     on;

   keepalive\_timeout 65;

   client\_header\_timeout 60;

   client\_body\_timeout 60;

   reset\_timedout\_connection on;

   send\_timeout 60;

   

   server\_tokens off;

   proxy\_next\_upstream    error timeout;

   

   proxy\_set\_header       Host $http\_host;    

   proxy\_set\_header       X-Real-IP $http\_x\_forwarded\_for;

   proxy\_set\_header       X-Forwarded-For $proxy\_add\_x\_forwarded\_for;

   

   proxy\_connect\_timeout  65;

   proxy\_send\_timeout     120;

   proxy\_read\_timeout     120;

   proxy\_buffer\_size      8k;

   proxy\_buffers          8 64k;

   proxy\_busy\_buffers\_size 128k;

   proxy\_temp\_file\_write\_size 128k;

   

   proxy\_http\_version 1.1;  

 limit\_conn\_zone $binary\_remote\_addr zone=one:10m;

##定义一个10M的名字为one的内存区域，用于记录访问频次；

   upstream dt\_cluster {

       server 172.1.1.230:17001;

       server 172.1.1.230:17002;

       server 172.1.1.230:17003;

       server 172.1.1.230:17004;

       keepalive 32;

       check interval=5000 rise=2 fall=3 timeout=10000;

     }

   

   lua\_package\_path "/usr/local/nginx/lua/lua-resty-redis/lib/?.lua;;";

   #gzip on;

   server {

       listen      7001;

       listen      7002;

       listen      7003;

       listen      7004;

       

       #server\_name localhost;

       #charset koi8-r;

       #access\_log logs/host.access.log  main;

       set $resp\_body "";      

                               location /OpenEbus {

                                              proxy\_pass http://dt\_cluster;

                                 #              include body\_filter\_by\_lua.conf;

                                 #               lua\_need\_request\_body on;

                                 #               body\_filter\_by\_lua

                                 #                              local resp\_body = string.sub(ngx.arg[1], 1, 1000)

                                 #                              ngx.ctx.buffered  = (ngx.ctx.buffered or "") .. resp\_body

                                 #                              if ngx.arg[2] then

                                 #                                     ngx.var.resp\_body = ngx.ctx.buffered

                                 #                              end

                                 #               ;

                               

limit\_conn one  250;

##限制并发连接最多250个；

}

                                       

                               location /hello {

                                                default\_type text/plain;

                                                content\_by\_lua ngx.say("hello, lua");

                                       }

                                       

location /mockService {

                       proxy\_pass http://dt\_cluster;

                    }

       location / {

                         return 403;

                                       }      

   }

}

通过使用limit\_conn\_zone 和limit\_conn 对某个目录或指定后缀，比如.html或.jpg进行并发连接限制。有了连接数限制，相当于限制了客户端浏览器和Nginx之间的管道个数，浏览器通过管道运输请求，如同向自来水管中放水，水的流速和压力对于管道另外一端是有影响的。为了防止不信任的客户端通过这个管道疯狂发送请求，消耗CPU内存等资源，以及防止URL不断发出连接请求，必须对请求的速度进行限制，如同对水流速度限制一样。