Nginx四/七层负载均衡
OSI(open system interconnection)开放式系统互联模型,这个是由国际标准化组织ISO指定的一个不基于具体机型、操作系统或公司的网络体系结构。该模型将网络通信的工作分为七层。
物理层(Physical Layer):
负责传输原始的比特流(0和1)。
定义硬件设备间的物理连接,包括电压、电缆、传输速率等。
数据链路层(Data Link Layer):
负责节点之间的数据帧传输和错误检测。
包括媒体访问控制(MAC)和逻辑链路控制(LLC)。
例如:以太网(Ethernet)、Wi-Fi。
网络层(Network Layer):
负责数据包的传输和路由选择,确保数据从源端到达目标端。
使用IP地址进行路由和转发。
例如:IP(互联网协议)、ICMP(互联网控制消息协议)。
传输层(Transport Layer):
提供端到端的通信和数据传输控制。
负责分割数据并保证数据的完整性和顺序。
例如:TCP(传输控制协议)、UDP(用户数据报协议)。
会话层(Session Layer):
负责建立、管理和终止应用程序之间的会话。
处理会话管理、同步和对话控制。
例如:NetBIOS、RPC(远程过程调用)。
表示层(Presentation Layer):
负责数据的翻译、加密、解密和压缩。
确保不同系统之间的数据格式一致。
例如:SSL/TLS(安全套接层/传输层安全)、JPEG、MPEG。
应用层(Application Layer):
提供网络服务和应用程序接口。
直接面向用户,提供应用程序间的通信。
例如:HTTP(超文本传输协议)、FTP(文件传输协议)、SMTP(简单邮件传输协议)。
四层负载均衡
所谓四层负载均衡指的是OSI七层模型中的传输层,主要是基于IP+PORT的负载均衡
实现四层负载均衡的方式:
硬件:F5 BIG-IP、Radware等
软件:LVS、Nginx、Hayproxy等
七层负载均衡
七层负载均衡指的是在应用层,主要是基于虚拟的URL或主机IP的负载均衡
四层和七层负载均衡的区别
四层负载均衡数据包是在底层就进行了分发,而七层负载均衡数据包则在最顶端进行分发,所以四层负载均衡的效率比七层负载均衡的要高。
四层负载均衡不识别域名,而七层负载均衡识别域名。
处理四层和七层负载以为其实还有二层、三层负载均衡,二层是在数据链路层基于mac地址来实现负载均衡,三层是在网络层一般采用虚拟IP地址的方式实现负载均衡。
Nginx添加对四层负载均衡(基于TCP/UDP的负载均衡)的支持是在1.9.0版本中引入的,这个功能通过引入stream模块实现。
Nginx在1.9之后,增加了一个stream模块,用来实现四层协议的转发、代理、负载均衡等。stream模块的用法跟http的用法类似,允许我们配置一组TCP或者UDP等协议的监听,然后通过proxy_pass来转发我们的请求,通过upstream添加多个后端服务,实现负载均衡。
添加stream模块的支持
Nginx默认是没有编译这个模块的,需要使用到stream模块,需要先添加stream模块。
Nginx四层负载均衡的指令
stream指令
该指令提供在其中指定流服务器指令的配置文件上下文。和http指令同级。
语法 | stream { … } |
---|---|
默认值 | 无默认值 |
位置 | main |
用途 | 定义处理TCP/UDP流量的配置 |
upstream指令
该指令和http的upstream指令是类似的。
http {
upstream myapp {
server backend1.example.com;
server backend2.example.com weight=2;
server backend3.example.com down;
server backend4.example.com backup;
}
server {
listen 80;
location / {
proxy_pass http://myapp;
}
}
}
案例
根据请求的不同端都将请求分发到对应的服务器中
实现步骤
四台服务器
代理服务器:192.168.101.23
服务端1:192.168.101.18 redis1
服务端2:192.168.101.20 redis2
服务端3:192.168.101.87 tomcat
7.分别在192.168.101.18,192.168.101.20服务器的redis设置ip值
代理服务器配置
stream {
upstream redisbackend { #redis
server 192.168.101.18:6379;
server 192.168.101.20:6379;
}
upstream tomcatbackend { #tomcat
server 192.168.101.87:8090;
}
server {
listen 81;
proxy_pass redisbackend;
}
server {
listen 82;
proxy_pass tomcatbackend;
}
}
测试:访问代理服务器 端口81 进入到redis的负载均衡
可以看到对redis进行了轮询
访问82端口测试。进入到了tomcat页面
七层负载均衡
Nginx 实现七层负载均衡主要依赖于其 proxy_pass 代理模块。这个模块在 Nginx 的默认安装中通常是已经启用的,不需要进行额外的配置来启用它。
在 Nginx 中,负载均衡是通过反向代理实现的,具体来说,用户的请求会被根据指定的算法转发到一个由多个后端服务器组成的【upstream 服务器组】。以下是一些基本的步骤和配置示例。
upstream指令
该指令是配置文件中用来定义一组后端服务器的指令块。这个指令块允许你将请求分发到多个后端服务器,通常用于负载均衡和故障转移
语法 | upstream name {…} |
---|---|
默认值 | - |
位置 | http |
server指令
该指令用来指定后端服务器的名称和一些参数,可以使用域名、IP、端口或者unix socket。
语法 | server { … } |
---|---|
默认值 | 无默认值 |
位置 | upstream |
例如:
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{ #定义一组后端服务器的指令块
server 192.168.101.18:9001; #server指令
server 192.168.101.20:9001;
server 192.168.101.87:9001;
}
下面使用upstream与server执行测试负载均衡
环境:三台服务器分别是192.168.101.18,192.168.101.20,192.168.101.87
三台服务器的nginx配置
192.168.101.18
server{
listen 9001;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.101.18:9001</h1>';
}
192.168.101.20
server{
listen 9001;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.101.20:9001</h1>';
}
192.168.101.87
server{
listen 9001;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.101.87:9001</h1>';
}
代理服务器设置
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
server 192.168.101.18:9001;
server 192.168.101.20:9001;
server 192.168.101.87:9001;
}
页面访问测试
负载均衡状态
代理服务器在负责均衡调度中的状态有以下几个:
down 当前的server暂时不参与负载均衡
backup 预留的备份服务器
max_fails 允许请求失败的次数
fail_timeout 经过max_fails失败后, 服务暂停时间
max_conns 限制最大的接收连接数
down 该状态一般会对需要停机维护的服务器进行设置。
down:将该服务器标记为永久不可用,该代理服务器将不参与负载均衡。
upstream backend{
server 192.168.101.18:9001 down; #标记为不可用
server 192.168.101.20:9001;
server 192.168.101.87:9001;
}
访问测试
服务器只在两台之间轮询
backup
backup:将该服务器标记为备份服务器,当主服务器不可用时,该服务器将用来传递请求。
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
server 192.168.101.18:9001 down; #标记为不可用
server 192.168.101.20:9001 backup;
server 192.168.101.87:9001;
}
测试:
标记后无论刷新多少次都只有一台服务器可以用
模拟192.168.101.87不可用
使用防火墙关闭9001端口
访问测试
此时备用服务器192.168.101.20可以连接了
max_conns
max_conns=number:用来设置代理服务器同时活动链接的最大数量,默认为0,表示不限制,使用该配置可以根据后端服务器处理请求的并发量来进行设置。
设置最大连接数=10
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
server 192.168.101.18:9001 down;
server 192.168.101.20:9001 max_conns=10;
server 192.168.101.87:9001;
}
max_fails和fail_timeout
max_fails=number:设置允许请求代理服务器失败的次数,默认为1。
fail_timeout=time:设置经过max_fails失败后,服务暂停的时间,默认是10秒。
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
server 192.168.101.18:9001 down;
server 192.168.101.20:9001 backup;
server 192.168.101.87:9001 max_fails=3 fail_timeout=20;
}
模拟192.168.101.87:9001暂时不可用,关闭9001端口
测试 :快速失败超过3次后 ,将防火墙端口添加回来
负载均衡策略
nginx有如下六种负载均衡的算法
轮询 默认方式
weight 权重方式
ip_hash 依据ip分配方式
least_conn 依据最少连接方式
url_hash 依据URL分配方式
fair 依据响应时间方式
轮询
是upstream模块负载均衡默认的策略。每个请求会按时间顺序逐个分配到不同的后端服务器。轮询不需要额外的配置。默认weight=1。
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
server 192.168.101.18:9001 weight=1; #默认值,无论写不写都是weight=1
server 192.168.101.20:9001;
server 192.168.101.87:9001;
}
weight加权[加权轮询]
weight=number:用来设置服务器的权重,默认为1,权重数据越大,被分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的,所有此策略比较适合服务器的硬件配置差别比较大的情况。
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
server 192.168.101.18:9001 weight=10;
server 192.168.101.20:9001 weight=6;
server 192.168.101.87:9001 weight=2;
}
测试
访问次数
192.168.101.18 11
192.168.101.20 7
192.168.101.87 2
从结果看 87服务器是最少的访问量
18是最多的 其次是20
ip_hash
当对后端的多台动态应用服务器做负载均衡时,ip_hash指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来自某一个IP的用户在后端Web服务器A上登录后,在访问该站点的其他URL,能保证其访问的还是后端web服务器A。
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
ip_hash; # ip_hash设置
server 192.168.101.18:9001 weight=1;
server 192.168.101.20:9001 weight=1;
server 192.168.101.87:9001 weight=1;
}
访问测试
ip_hash的缺点是无法保证后端服务器的负载均衡,可能导致有些后端服务器接收到的请求多,有些后端服务器接收的请求少,而且设置后端服务器权重等方法将不起作用。
least_conn
使用最少连接数的服务器策略,把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。
server {
listen 8085;
server_name 127.0.0.1;
location / {
proxy_pass http://backend;
}
}
upstream backend{
least_conn;
server 192.168.101.18:9001;
server 192.168.101.20:9001;
server 192.168.101.87:9001;
}
测试通过jmeter对18服务器施加压力测试
但是最终好像没什么效果 18服务器并没有因为连接过多而被减少连接。
url_hash
当使用 url_hash 时,Nginx 会根据请求的URL计算出一个哈希值,然后将这个哈希值映射到后端服务器,以此来实现负载均衡。这种方式可以确保具有相同URL的请求总是被分发到同一个后端服务器,从而提高缓存的一致性和效率。
upstream backend{
hash $request_uri;
server 192.168.101.18:9001;
server 192.168.101.20:9001;
server 192.168.101.87:9001;
}
测试 :只要uri不变则返回的地址也不会变
地址发生变更 负载均衡的服务器也会发生变化
fair
fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面大小、加载时间长短智能的进行负载均衡。要使用第三方模块的fair负载均衡策略需要添加nginx-upstream-fair模块。
安装成功后测试
没有什么复杂业务,看不出什么效果
对特定资源实现负载均衡
upstream videobackend{
server 192.168.101.18:9001;
server 192.168.101.20:9001;
}
upstream filebackend{
server 192.168.101.87:9001;
server 192.168.101.89:9001;
}
server {
listen 8084;
server_name localhost;
location /video/ { #通过指定路径负载均衡
proxy_pass http://videobackend;
}
location /file/ {
proxy_pass http://filebackend;
}
}
对不同域名实现负载均衡
upstream homebackend{
server 192.168.101.18:9001;
server 192.168.101.20:9001;
}
upstream homelandbackend{
server 192.168.101.87:9001;
server 192.168.101.89:9001;
}
server {
listen 8085;
server_name www.home.com;
location / {
proxy_pass http://homebackend;
}
}
server {
listen 8086;
server_name www.homeland.com;
location / {
proxy_pass http://homelandbackend;
}
}
实现带有URL重写的负载均衡
server {
listen 8086;
server_name 127.0.0.1;
location /file/ {
rewrite ^(/file/.*) /server /$1 last; #正则表达式说明:"^(/file/.*)"请求以file开头且"."转义后的"*"匹配任意后缀结尾 然后将地址重写到 /server location "/$1"表示前面括号的内容拼接到/server后面 "last"表示在当前的server重新查找location
}
location /server {
proxy_pass http://backend;
}
}
upstream backend{
#hash $request_uri;
fair;
server 192.168.101.18:9001;
server 192.168.101.20:9001;
server 192.168.101.87:9001;
}
测试