张三开发了一个分享文学作品的网站,刚开始入驻的作者不多,可谓是人烟稀少。但入驻的作者们信念坚定,孜孜不倦地更新着自己的作品,功夫不负有心人,作品迎来了爆发式的阅读增长量,终于,大访问量使得应用服务器不堪重负,张三的网站开始频繁出现卡顿、无响应等故障。
为了分摊服务器的压力,张三扩充了服务器的数量,将压力分摊到多台服务器上,原本不堪重负的网站再次稳定,读者们又可以快乐地阅读了。
这个案例中,早期时候,网站的流量比较小,单台服务器足以满足业务需求,但随着不断地发展,网站流量越来越大,单台服务器的性能局限和单点故障的问题就凸显出来
,因此需要扩展为多台服务器组成集群,既能解决单点故障,也可以提升网站的稳定性
。
正所谓一根筷子容易折,一把筷子难折断,这也是我们通常所说的水平扩展。与水平扩展相对应的是垂直扩展,垂直扩展意味着还是单台应用服务器,提升的是例如服务器的硬盘、内存以及CPU等的性能,一旦达到上限,性能就再与无法提升,这也是垂直扩展的局限性,同时,单点故障的问题还是存在。
因此,我们通常会采用水平扩展。
那么,在水平扩展为多台服务器之后,又怎么来进行请求的分发呢?
没错,负载均衡
在这个时候登场。那么什么是负载均衡呢?
1.什么是负载均衡
负载均衡(Load Balance):这里的含义是指通过一定的算法将请求进行分发到不同的应用服务器上,以减少单台服务器的压力。
2.Nginx实现负载均衡
我们知道Nginx可以反向代理服务器,将请求代理到目标服务端,目标服务端仅仅是单台服务器,该服务器独自默默承受了所有的压力。
如下图所示:
就像我们前面的案例一样,随着业务的不断发展,单台服务器势必无法支持业务带来的负载,单台服务器水平扩展为多台服务器集群。
因此,Nginx在反向代理的基础上,添加了ngx_http_upstream_module
模块,在反向代理的同时,能够根据一定的负载均衡算法就请求分发到集群中的不同服务器。
如下图所示:
言归正传,如何实现Nginx负载均衡呢?
先来看看官方给我们的示例:
文档地址:https://nginx.org/en/docs/http/ngx_http_upstream_module.html
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;
}
}
上半部分upstream
指令是负载均衡配置,下半部分server
指令是我们熟悉的反向代理配置。因此,我们重点关注upstream
指令。
是不是已经迫不及待地想要搞清楚upstream
指令相关的操作啦。话不多说,走起。
2.1 upstream指令
该指令可以定义一个由多台被代理服务器组成的服务器组,作为这些服务器的统一入口,并且每台服务器都可以配置不同的端口,更加的灵活。
作用域:http
语法:upstream name { … }
并且,在默认情况下,采用加权轮询算法在服务器之间分配请求,有点雨露均沾的意思哈。😄
如果在与服务器通信的过程中发生错误,请求将会被传递到下一台服务器,依此类推,如果无法从任何一台服务器获得成功的响应,则客户端将接收到最后一台服务器返回的结果。
示例:
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;
}
到这里我们已经搞清楚了upstream
指令的含义,但是在其定义的块中多了像server
、weight
、backup
这样的陌生指令。
古话说,心急吃不了热豆腐,客观别急,我们一一道来。
2.2 server指令
该指令定义被代理服务器的地址和其他的一些参数,例如weight
、backup
。
作用域:upstream
语法:server address [parameters];
示例:
server backend1.example.com weight=5;
server backend2.example.com:8080;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
那么,我们可以定义哪些参数呢?各个参数的作用是什么?
2.2.1 weight
设置被代理服务器的权重,默认值为1。权重值越大,被访问的次数就越多。我们可以根据服务器的处理能力来设置权重值。
server backend1.example.com weight=1;
2.2.2 max_conns
限制被代理服务器的最大连接数,默认值为0,也就意味着没有限制。
server backend1.example.com max_conns=0;
2.2.3 fail_timeout
当被代理服务器被认定为不可用时,设置其不可用时间。默认值为10s。
server backend1.example.com max_fails=3 fail_timeout=10;
2.2.4 max_fails
设置与被代理服务器通信失败后的最大重试次数,并与fail_timeout进行配合,认定服务器在该段时间内不可用。默认值为1,如果设置为0,则禁用重试。
server backend1.example.com max_fails=3 fail_timeout=10;
2.2.5 backup
将被代理服务器标记为备用服务器。当主服务器不可以用时,备用服务器才会上场。
🔔Tips:该参数不可与hash、ip_hash以及random负载均衡算法一起使用。
server backend1.example.com backup;
2.2.6 down
将指定的被代理服务器标记为不可用,不参与负载均衡过程。
server backend1.example.com backup down;
2.3 负载均衡策略
既然是负载均衡,那么肯定涉及到负载均衡的算法。
Nginx为我们支持多种负载均衡算法,例如加权轮询
、hash
、ip_hash
、least_conn
、least_time
、random
。
下面我们来分别看看这些负载均衡算法。
2.3.1 加权轮询
这是Nginx的默认负载均衡算法。其在轮询的基础上加入了权重,前者是雨露均沾,后者是重点对象特殊照顾。
如果我们将所有被代理的服务器都设置为weight=1,也就是普通的轮询算法。
普通轮询:
upstream backend {
server backend1.example.com weight=1;
server backend2.example.com weight=1;
}
加权轮询:
upstream backend {
server backend1.example.com weight=1;
server backend2.example.com weight=5;
}
2.3.2 hash
语法:hash key [consistent];
hash算法,我们可以指定文本或者变量,如果指定文本,则意味着请求都会被传递到同一个服务器,因此,通常我们使用变量来进行hash。例如:
upstream backend {
hash $request_uri;
server backend1.example.com;
server backend2.example.com;
}
这样就可以将同一个URI传递到同一个服务器。
🔔Tips:使用hash算法时,权重将失效。
2.3.3 ip_hash
该算法根据客户端的IP地址在被代理服务器之间分配请求,同时考虑权重。该算法会将同一客户端的请求始终传递到同一服务器。
upstream backend {
ip_hash;
server backend1.example.com weight=5;
server backend2.example.com;
}
🔔Tips:在1.2.2和1.3.1版本之前,不支持指定权重。
2.3.4 least_conn
该算法将请求传递给具有最少活动连接数的服务器,同时考虑权重。
upstream backend {
least_conn;
server backend1.example.com weight=1;
server backend2.example.com weight=5;
}
2.3.5 least_time
该算法将请求传递到平均响应时间和活动连接数最少的服务器,同时考虑权重。
语法:least_time header | last_byte [inflight];
header
:意味着使用接收响应标头的时间。last_byte
:意味着使用接收完整响应的时间。
upstream backend {
least_time last_byte;
server backend1.example.com weight=1;
server backend2.example.com weight=5;
}
🔔Tips:该算法目前只在商业订阅版提供。
2.3.6 random
该算法将请求传递给随机选择的服务器,同时考虑权重。
语法:random [two [method]];
two
:可选参数,如果启用则随机选择两个被代理服务器,并使用least_conn
的方法来选择其中一个。
method
:指定选择方法,可选值为least_conn
和least_time
,least_time
仅商业订阅版可用。
示例:
upstream backend {
random two least_conn;
server backend1.example.com weight=1;
server backend2.example.com weight=5;
}
以上就是Nginx实现负载均衡的全部内容,Nginx是多模块化的,还有很多高级功能,我们后面继续探索。