nginx的日常使用之负载均衡_nginx负载均衡-爱代码爱编程
负载均衡在nginx中的使用
文章目录
目录
前言
接着前文对nginx反向代理的介绍,这篇文章将继续介绍负载均衡在nginx中的使用
一、负载均衡是什么?
我们可以先看下维基百科中的解释:
负载平衡(英语:load balancing)是一种电子计算机技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。 使用带有负载平衡的多个服务器组件,取代单一的组件,可以通过冗余提高可靠性。负载平衡服务通常是由专用软件和硬件来完成。 主要作用是将大量作业合理地分摊到多个操作单元上进行执行,用于解决互联网架构中的高并发和高可用的问题。
我们可以很清晰的看到负载均衡首先是一种技术,旨在在多台服务器、网络链接、CPU或其他资源之间分配工作负载,以优化资源使用、最大化吞吐量、最小化响应时间,并避免任何单一资源的过载。负载均衡可以在多种不同层次上实现,如应用层、传输层和网络层。
在工作中最直观的感受就是当一台服务器无法处理大量的并发请求时,可以设立集群架构由多个服务器来处理大量的请求,而这时负载均衡服务器就可以单独提供一个集群的访问入口,你只需要访问负载均衡服务器的地址,而你最后具体访问到集群中的哪台服务器则有负载均衡服务器按照事先预设好的策略做决定。
二、负载均衡的类型和应用
1.硬件负载均衡器:
• 这类负载均衡器通常存在于数据中心,是物理设备。例如,F5 Big-IP 和 Cisco的负载均衡器就是行业内知名的硬件负载均衡解决方案。
• 它们通常支持更高的数据处理速度和复杂的配置。
2.软件负载均衡器
• 这类负载均衡器运行在普通服务器上,不需要专用硬件。常见的软件负载均衡器包括 Nginx、Apache HTTP Server、HAProxy等。
(1)Nginx
Nginx 作为反向代理和负载均衡器,可以根据不同的算法(如轮询、最少连接数等)来分配客户端请求到后端服务器。Nginx 也支持SSL/TLS终端,可以减轻后端服务器的负担。
(2)HAProxy
HAProxy 提供高可用性、负载均衡和基于TCP和HTTP应用的代理。它特别擅长处理大量并发连接,并且是许多高流量网站的首选。
(3)Apache HTTP Server
Apache HTTP Server 可以通过mod_proxy_balancer模块提供负载均衡功能。Apache的负载均衡器支持多种调度算法,包括基于请求或会话的负载均衡。
3. 云负载均衡器:
• 主要云服务提供商如AWS、Azure和Google Cloud提供的负载均衡服务。这些负载均衡器可以跨全球或特定地区动态分配网络或应用流量。
(1)AWS Elastic Load Balancing (ELB)
AWS ELB 可以自动分配进入的应用流量和网络流量。ELB支持三种类型的负载均衡:应用负载均衡器、网络负载均衡器和经典负载均衡器。
(2)Azure Load Balancer
Azure 提供的负载均衡器确保应用的可靠性和可用性,可以在本地数据中心和云之间进行无缝连接。
(3)Google Cloud Load Balancer
Google Cloud 的负载均衡器支持TCP/UDP负载均衡、HTTP(S) 负载均衡、SSL代理和TCP代理。
三、负载均衡的好处
• 增强可用性和可靠性:通过在多台服务器之间分配流量,确保系统即使在部分组件失败时也能持续运行。
• 提高性能:通过分散处理负载,负载均衡能够减少对单一服务器的压力,从而提高响应速度和处理能力。
• 可伸缩性:当需求增加时,可以通过添加更多服务器来轻松扩展服务容量。
• 灵活性和成本效率:软件和云负载均衡解决方案提供了成本效率高、部署快速且易于管理的优势。
而本文我们主要介绍负载均衡在nginx当中的具体使用方法
四、负载均衡在nginx中的使用
服务器准备:准备一台nginx服务器作为负载均衡服务器,准备两台应用服务器作为被代理的后端服务。
Nginx负载均衡服务器 :发行版Centos7.6 ip 192.168.50.165
后端服务器代码展示:
后端服务器A :ip 192.168.50.173
package com.example.nginxdemo.controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class HelloController {
@GetMapping("/haha")
public String generateUrl() {
return "this a nginx A";
}
}
后端服务器 B : ip 192.168.50.147
package com.example.nginxdemo.controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class HelloController {
@GetMapping("/haha")
public String generateUrl() {
return "this a nginx B";
}
}
通过页面返回的A和B来区分后端服务的访问
1、基本的nginx负载均衡配置示例
http {
upstream myapp { #upstream 指令定义了一个服务器组 myapp,其中包含两个服务器
server server1.example.com;
server server2.example.com;
}
server {
listen 80;
location / { #server 块定义了一个接受客户端请求的服务器,所有的 / 路径的请求都会被代理到 myapp 服务器组
proxy_pass http://myapp;
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_set_header X-Forwarded-Proto $scheme;
}
}
}
在这个配置中我们使用在upstream指令定义了一个服务器组myapp,这个服务器组中的两台服务器就是我们需要分配流量的后端服务器,在负载均衡的上下文中,Nginx 接收来自客户端的请求,并根据预定的策略将这些请求转发到我们预设的upstream服务器组的服务器中。这样可以保证单个服务器不会因过载而崩溃,同时提高了请求处理的速度和效率。
2、Nginx 负载均衡的关键特性
(1)Nginx自带的负载均衡方法:
• 轮询(Round Robin):这是默认的负载均衡方法,也是本文着重介绍的方法,请求按顺序依次分配到每个服务器,当列表末尾的服务器被分配请求后,下一个请求再从列表开头的服务器开始分配。
优点:简单且高效,不需要额外的配置。在服务器规格相似且处理能力接近时表现良好。
缺点:不考虑服务器的当前负载和性能。如果后端服务器的处理能力不均匀,可能导致资源分配不均(需要通过weight配置来根据服务器的配置进行请求分发)。
适合场景:服务器配置相同,处理能力相似,且对负载均衡算法的复杂性要求不高的场景。
• 最少连接数(Least Connections):把请求转发给连接数较少的后端服务器,考虑到服务器当前的负载情况,试图保持后端服务器之间的活动连接数量大致相等。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
优点:考虑了服务器的当前负载,可以更平衡地分配请求,在处理长时间连接或会话较多的应用(如WebSocket)时尤为有效。
缺点:算法相对复杂,对服务器状态的检查要求更频繁,可能会有更高的管理开销。
适用场景:后端服务器处理能力存在差异,适合处理长连接和动态变化的请求负载。
• IP散列(IP Hash):请求根据客户端的 IP 地址进行散列哈希计算,确保来自同一 IP 地址的客户端请求总是被发送到同一台服务器。因为我们是负载均衡系统,每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,而ip_hash指令解决这个问题,固定ip访问固定的后端服务器可以解决session不能跨服务器的问题。
优点:保证了同一用户的请求总是由同一台服务器处理,可以在无状态的服务器集群中保持用户会话,减少了不同服务器之间缓存数据的冗余。
缺点:分配不够平均,若某一 IP 段的流量很大,可能导致某些服务器过载而其他服务器闲置。当服务器列表变动时,现有的 IP 哈希分配可能会被打乱,影响用户会话。
适用场景:需要会话持久性的应用,如在线购物的购物车或者用户分布相对均匀的场景。
(2)第三方负载均衡方法
还有另外两种需要编译第三方模块的负载均衡方法,这里也做下简单介绍
• 公共负载均衡(Fair Load Balancing)(第三方):通过评估后端服务器的响应时间或当前负载(如活跃连接数)来分配请求,意图实现真正意义上的“公平”,即让每台服务器根据其当前能力承担相应的负载。通常是通过 Nginx 的第三方模块 nginx-upstream-fair 实现的。这种算法的目的是根据后端服务器的响应时间(和/或当前的活跃连接数)动态地分配请求。简而言之,响应时间短的服务器会获得更多的请求。
优点:Fair 算法具有动态响应性能根据后端服务器的实时性能(如响应时间)来调整流量分配,从而优化整体性能。并且用的负载平衡特性确保没有单个服务器因为过载而成为瓶颈。
缺点:此算法相对比较复杂,相比简单的轮询或IP哈希算法,Fair 算法需要更多的运算来跟踪和计算服务器的响应时间,并且监控服务器响应时间可能增加额外的性能开销,带来更大的资源消耗。
适用场景:在服务器性能不均等的环境中,尤其适用于那些服务器响应时间相差显著的场景或者动态内容生成时间较长的应用,如大型网站或多媒体服务。
• URL 哈希负载均衡(URL Hash Load Balancing)(第三方):通过对请求的 URL 进行哈希计算,并根据计算结果将请求路由到特定的服务器。这种方法保证了同一个 URL 的请求总是被同一台服务器处理,适用于需要会话持久性的场景。url_hash 是通过Nginx第三方模块nginx-module-vts实现的,确保每个特定的 URL 总是被映射到同一台服务器上(只要服务器列表保持不变)。
优点:此算法拥有会话持久性,通过确保来自相同 URL 的请求总是路由到同一台服务器,可以维护用户的会话状态,对缓存交付友好,减少了缓存重复,因为相同的资源请求总是由同一台服务器处理。
缺点:此算法对负载分配并不平衡,某些 URL 可能会更频繁地被请求,导致某些服务器负载较重。并且还存在缩放问题,当动态调整服务器时,URL 到服务器的映射可能会改变,影响缓存和会话持久性。
适用场景:需要会话持久性的应用,例如在线购物车、用户定制化内容或者是高缓存利用率场景,如静态内容重的网站。
这些算法需要通过特定的 Nginx 第三方模块来实现,如 nginx-upstream-fair 或 nginx-module-vts 等,这些模块提供了 Nginx 在这些高级负载均衡策略上的支持。使用这些模块可以让 Nginx 更好地适应复杂和特定的负载均衡需求。
3、负载均衡的配置过程
(1)轮询(Round Robin)
Nginx 配置文件展示(请自行在服务器上找到自己的nginx.conf配置文件进行配置):
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream myapp {
server 192.168.50.173:8080 weight=1;
server 192.168.50.147:8080 weight=1;
}
server {
listen 80 default_server;
server_name 192.168.50.165;
root /etc/nginx/html;
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://myapp;
}
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
以上是最基本的轮询负载均衡配置,weight为负载的权重,用于指定轮询几率,weight不写时的默认值为1,weight的数值与访问比率成正比,weight越大的服务器,相同的访问次数中,被访问到的几率也就越大,这里我们设置两台服务器的权重都为默认值1,代表我们会轮流访问这两台服务器上的8080端口的应用服务。
然后我们重载165服务器上的nginx,并进行访问,多次点击刷新,会发现页面返回的内容依次返回A和B,代表我们的负载均衡配置成功
接下来让我们继续修改配置文件添加一些特殊参数来完善轮询负载均衡的配置
尽管基本的轮询算法本身不需要特殊参数,但是Nginx 允许你在使用轮询时配置几个额外的参数来优化负载均衡的行为。这些参数主要关注服务器的权重以及应对服务器故障的处理。以下是可以用于调整轮询算法行为的参数:
max_fails :允许请求失败的最大次数,当超过这个次数后,服务器被认为是不健康的,会暂时从轮询中移除,并返回proxy_next_upstream模块定义的错误,并切换到下一个服务器。
upstream myapp {
server 192.168.50.173:8080 max_fails=3;
server 192.168.50.147:8080 max_fails=3;
}
server {
listen 80;
location / {
proxy_pass http://myapp;
# 当后端服务器返回特定错误时,切换到下一个服务器
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
# timeout 当后端服务器在规定时间内没有响应时,将请求转发到下一个服务器。
# invalid_header 当后端服务器返回无效的响应头时,将请求转发到下一个服务器。
# http_500 当后端服务器返回 500(服务器内部错误)时,将请求转发到下一个服务器。
# http_502 当后端服务器返回 502(错误网关)时,将请求转发到下一个服务器。
# http_503 当后端服务器返回 503(服务不可用)时,将请求转发到下一个服务器。
# http_504 当后端服务器返回 504(网关超时)时,将请求转发到下一个服务器。
}
}
fail_timeout :在这段时间内,如果服务器达到了 max_fails 指定的失败次数,则认为服务器不健康,暂时从轮询中移除,并返回proxy_next_upstream模块定义的错误,并切换到下一个服务器。
upstream myapp {
server 192.168.50.173:8080 fail_timeout=30s;
server 192.168.50.147:8080 fail_timeout=30s;
}
server {
listen 80;
location / {
proxy_pass http://myapp;
# 当后端服务器返回特定错误时,切换到下一个服务器
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
# timeout 当后端服务器在规定时间内没有响应时,将请求转发到下一个服务器。
# invalid_header 当后端服务器返回无效的响应头时,将请求转发到下一个服务器。
# http_500 当后端服务器返回 500(服务器内部错误)时,将请求转发到下一个服务器。
# http_502 当后端服务器返回 502(错误网关)时,将请求转发到下一个服务器。
# http_503 当后端服务器返回 503(服务不可用)时,将请求转发到下一个服务器。
# http_504 当后端服务器返回 504(网关超时)时,将请求转发到下一个服务器。
}
}
backup : 标记某个服务器为备份服务器,只有当其他非备份服务器都不可用时,才会向备份服务器发送请求。
upstream myapp {
server 192.168.50.173:8080 backup;
server 192.168.50.147:8080;
}
down :标记某个服务器为停机状态,表示当前服务器不参与负载。
upstream myapp {
server 192.168.50.173:8080 backup;
server 192.168.50.147:8080 down;
}
通过以上这些参数使得基本的轮询算法更加灵活和强大,可以根据实际需求进行相应的配置调整,以达到更优的负载均衡效果。在配置时,我们更要考虑服务器的处理能力、网络条件以及预期的流量分布,比如集群服务器中一台服务器为8核16G,一台为4核8G,这时我们完全可以配置8核16G的服务器的权重多一些,已让配置更高的服务器来处理更多的请求,可以避免4核8G的服务器因配置原因导致宕机问题,合理运用这些可以有效地来优化系统的整体性能和可靠性。
(2)最少连接数(Least Connections)
Nginx 配置文件展示(请自行在服务器上找到自己的nginx.conf配置文件进行配置):
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream myapp {
least_conn;
server 192.168.50.173:8080;
server 192.168.50.147:8080;
}
server {
listen 80 default_server;
server_name 192.168.50.165;
root /etc/nginx/html;
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://myapp;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
只需在upstream指令定义的服务器组中添加 least_conn; 便可将算法配置切换为最少连接数算法
轮询算法中的特殊参数依然适用于最少连接算法。
(3)IP散列(IP Hash)
Nginx 配置文件展示(请自行在服务器上找到自己的nginx.conf配置文件进行配置):
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream myapp {
ip_hash;
server 192.168.50.173:8080 weight=1;
server 192.168.50.147:8080 weight=1;
}
server {
listen 80 default_server;
server_name 192.168.50.165;
root /etc/nginx/html;
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://myapp;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
只需在upstream指令定义的服务器组中添加 ip_hash; 便可将算法配置切换为IP散列算法
轮询算法中的特殊参数backup不能使用于IP散列算法,其他参数依然适用于IP散列算法。
(4)第三方策略算法
由于这些算法需要通过特定的 Nginx 第三方模块来实现,如 nginx-upstream-fair 或 nginx-module-vts,上文以做简单介绍,这里就只展示代码配置,不再做其他描述。
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream myapp {
fair; # 公平负载均衡
server 192.168.50.173:8080 weight=1;
server 192.168.50.147:8080 weight=1;
}
server {
listen 80 default_server;
server_name 192.168.50.165;
root /etc/nginx/html;
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://myapp;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream myapp {
hash $request_uri; # url哈希负载均衡
server 192.168.50.173:8080 weight=1;
server 192.168.50.147:8080 weight=1;
}
server {
listen 80 default_server;
server_name 192.168.50.165;
root /etc/nginx/html;
include /etc/nginx/default.d/*.conf;
location /haha { # 基于url规则进行hash策略
proxy_pass http://myapp;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
4、健康检查
Nginx 负载均衡还可以配置来检查后端服务器的健康状况,自动剔除故障节点,确保流量只被转发到健康的服务器。不过Nginx 开源版本不直接支持被动的健康检查,Nginx 的商业版本提供了更高级的健康检查功能,包括主动健康检查。开源版本依赖于手动移除或通过第三方模块实现,不过开源版本中有一些机制和指令也可以帮助管理后端服务器的可用性,上文中提到的proxy_next_upstream 指令就是其中之一。
这不是一个独立的模块,而是 Nginx 开源版本中的一个配置指令,用于处理请求时后端服务器出现问题的情况。这个指令决定在什么情况下 Nginx 应该将请求转发到下一个服务器(即所谓的”被动”健康检查)。它不会主动检测服务器是否健康,而是在尝试与服务器交互时如果遇到特定的错误或问题,则尝试其他服务器。这种方式可以在某种程度上减轻单个服务器故障的影响
使用 proxy_next_upstream 指令非常适合以下场景:
• 增强系统的健壮性:当一个后端服务器因为故障无法处理请求时,自动尝试另一个服务器。
• 负载分散:在某些故障情况下自动重新尝试可以防止某一台服务器的暂时故障影响整个系统的可用性。
虽然这提供了一种应对服务器故障的方法,但它并不替代真正的健康检查机制。在 Nginx 的商用版本中,可以使用内置的健康检查功能主动检测后端服务器的健康状况,这样可以更有效地管理服务器的健康状态,而不仅仅是在请求失败时才做出响应。在开源版本中,如果需要更高级的健康检查,可以考虑使用第三方模块或集成外部健康检查工具。
总结
Nginx 作为一个免费开源的负载均衡器可以提供灵活、高效的流量管理,通过其多种负载均衡算法和配置选项,大大增强应用的可靠性和响应性。它的配置灵活性使其成为前端负载均衡的理想选择。在处理大量并发连接时,Nginx 表现尤为出色,是很多高性能网站和应用的首选。本文内容仅作为学习参考使用,如有不足或者错误欢迎指正。