赞
踩
负载均衡(Load balancing)在不同的领域有不同的概念。其基本概念是为了减轻某个或某些实体的负载,将任务通过某种策略分配到多个实体上去,实现负载在不同实体间的平衡。
七层就是基于URL等应用层信息的负载均衡。从第七层"应用层"开始,根据虚拟的url或IP,主机名接收请求,再转向相应的处理服务器。七层负载均衡器也称作七层交换机,即L7 switch(七层交换),OSI的最高层,应用层。此时,该Load Balancer能理解应用协议。如:HAProxy、Nginx等。
四层就是基于IP+端口的负载均衡,是在三次负载均衡的基础上,即从第四层"传输层"开始,使用"ip+port"接收请求,再转发到对应的机器。四层负载均衡器也称作四层交换机,即L4 switch(四层交换),在OSI第4层工作,此种Load Balance不理解应用协议(如HTTP/FTP/MySQL等等)。如:LVS、F5、深信服AD等。
以常见的TCP为例,负载均衡设备在接收到第一个来自客户端的SYN 请求时,即通过上述方式选择一个最佳的服务器,并对报文中目标IP地址进行修改(改为后端服务器IP),直接转发给该服务器。TCP的连接建立,即三次握手是客户端和服务器直接建立的,负载均衡设备只是起到一个转发动作。在某些部署情况下,为保证服务器回包可以正确返回给负载均衡设备,在转发报文的同时可能还会对报文原来的源地址进行修改。
实现四层负载均衡的有:
四层负载均衡仅能转发TCP/IP协议、UDP协议、通常用来转发端口,如:tcp/22、udp/53;
四层负载均衡可以用来解决七层负载均衡端口限制问题;(七层负载均衡最大使用65535个端口号)
四层负载均衡可以解决七层负载均衡高可用问题;(多台后端七层负载均衡能同时的使用)
四层的转发效率比七层的高得多,但仅支持tcp/ip协议,不支持http和https协议;
通常大并发场景通常会选择使用在七层负载前面增加四层负载均衡。
Nginx要实现七层负载均衡需要用到proxy_pass代理模块配置。Nginx默 认安装支持这个模块,我们不需要再做任何处理。Nginx的负载均衡是 在Nginx的反向代理基础上把用户的请求根据指定的算法分发到一组 【upstream虚拟服务池】。
该指令是用来定义一组服务器,它们可以是监听不同端口的服务器,并 且也可以是同时监听TCP和Unix socket的服务器。服务器可以指定不同 的权重,默认为1。
语法 | upstream name {…} |
---|---|
默认值 | — |
位置 | http |
该指令用来指定后端服务器的名称和一些参数,可以使用域名、IP、端
口或者unix socket。
语法 | server name [paramerters] |
---|---|
默认值 | — |
位置 | upstream |
我们搭建一个测试环境,部署三个web应用,分别为serverA , serverB,serverC,并在hosts文件中配置测试域名。
127.0.0.1 www.test-nginx.com
server { listen 9091; server_name localhost; default_type "text/plain;charset=utf-8"; return 200 "hello,I am server A !"; } server { listen 9092; server_name localhost; default_type "text/plain;charset=utf-8"; return 200 "hello,I am server B !"; } server { listen 9093; server_name localhost; default_type "text/plain;charset=utf-8"; return 200 "hello,I am server C !"; }
upstream myweb {
server 127.0.0.1:9091;
server 127.0.0.1:9092;
server 127.0.0.1:9093;
}
代理服务器在负责均衡调度中的状态有以下几个:
状态 | 概述 |
---|---|
down | 当前的server暂时不参与负载均衡 |
backup | 预留的备份服务器 |
max_fails | 允许请求失败的次数 |
fail_timeout | 经过max_fails失败后, 服务暂停时间 |
max_conns | 限制最大的接收连接数 |
将该服务器标记为永久不可用,那么该代理服务器将不参与负载 均衡。
upstream myweb {
server 127.0.0.1:9091 down;
server 127.0.0.1:9092;
server 127.0.0.1:9093;
}
server {
listen 80;
server_name localhost;
location /proxy/ {
proxy_pass http://myweb/web/;
}
}
发送10次请求访问地址:http://www.test-nginx.com/proxy/hello,输出如下:
hello,I am server B !
hello,I am server C !
hello,I am server B !
hello,I am server C !
hello,I am server B !
hello,I am server C !
hello,I am server B !
hello,I am server C !
hello,I am server B !
hello,I am server C !
将该服务器标记为备份服务器,当主服务器不可用时,将用来传 递请求。
upstream myweb {
server 127.0.0.1:9091 down;
server 127.0.0.1:9092 backup;
server 127.0.0.1:9093;
}
server {
listen 80;
server_name localhost;
location /proxy/ {
proxy_pass http://myweb/web/;
}
}
max_conns=number:用来设置代理服务器同时活动链接的最大数量, 默认为0,表示不限制,使用该配置可以根据后端服务器处理请求的并发 量来进行设置,防止后端服务器被压垮。
max_fails=number:设置允许请求代理服务器失败的次数,默认为1。
fail_timeout=time:设置经过max_fails失败后,服务暂停的时间,默认 是10秒。
upstream myweb {
server 127.0.0.1:9091 down;
server 127.0.0.1:9092 backup;
server 127.0.0.1:9093 max_fails=1 fail_timeout=10;
}
server {
listen 80;
server_name localhost;
location /proxy/ {
proxy_pass http://myweb/web/;
}
}
介绍完Nginx负载均衡的相关指令后,我们已经能实现将用户的请求分 发到不同的服务器上,那么除了采用默认的分配方式以外,我们还能采 用什么样的负载算法?
Nginx的upstream支持如下六种方式的分配算法,分别是:轮询,加权轮询,Ip hash。下面我们对其一一进行演示。
1. 轮询(默认)
是upstream模块负载均衡默认的策略。每个请求会按时间顺序逐个分配 到不同的后端服务器。轮询不需要额外的配置。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
worker_processes 4; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; 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; sendfile on; keepalive_timeout 65; #设置虚拟主机的基本信息 upstream myweb { server 127.0.0.1:9091; server 127.0.0.1:9092; server 127.0.0.1:9093; } server { listen 80; server_name localhost; location /proxy/{ proxy_pass http://myweb/web/; } location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
发送10次请求访问地址:http://www.test-nginx.com/proxy/hello,输出如下:
hello,I am server A !
hello,I am server B !
hello,I am server C !
hello,I am server A !
hello,I am server B !
hello,I am server C !
hello,I am server A !
hello,I am server B !
hello,I am server C !
hello,I am server A !
2. 加权轮询
weight=number:用来设置服务器的权重,默认为1,权重数据越大,被 分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的 后端服务器硬件配置进行调整的,此策略比较适合服务器的硬件配 置差别比较大的情况。
upstream myweb {
server 127.0.0.1:9091 weight=1;
server 127.0.0.1:9092 weight=2;
server 127.0.0.1:9093 weight=2;
}
发送10次请求访问地址:http://www.test-nginx.com/proxy/hello,输出如下:
hello,I am server A !
hello,I am server B !
hello,I am server C !
hello,I am server B !
hello,I am server C !
hello,I am server A !
hello,I am server B !
hello,I am server C !
hello,I am server B !
hello,I am server C !
3. Ip hash 算法
当对后端的多台动态应用服务器做负载均衡时,ip_hash指令能够将某个 客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来 自某一个IP的用户在后端Web服务器A上登录后,在访问该站点的其他 URL,能保证其访问的还是后端web服务器A。每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream myweb {
server 127.0.0.1:9091;
server 127.0.0.1:9092;
server 127.0.0.1:9093;
ip_hash;
}
发送10次请求访问地址:http://www.test-nginx.com/proxy/hello,输出如下:
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
4. least_conn
最少连接,把请求转发给连接数较少的后端服务器。轮询算法是把请求 平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用 的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn 这种方式就可以达到更好的负载均衡效果。
upstream myweb {
least_conn;
server 127.0.0.1:9091;
server 127.0.0.1:9092;
server 127.0.0.1:9093;
}
server {
listen 80;
server_name localhost;
location /proxy/ {
proxy_pass http://myweb/web/;
}
...
}
5. fair(第三方)
fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面 大小、加载时间长短智能的进行负载均衡。那么如何使用第三方模块的 fair负载均衡策略。需要使用nginx-upstream-fair-master 插件。
下载:nginx-upstream-fair-master。
使用./configure命令将资源添加到Nginx模块中
./configure --add-module=/Users/yangyanping/Downloads/soft/nginx-upstream-fair-master
编译,编译可能会出现如下错误,ngx_http_upstream_srv_conf_t结构中缺少 default_port
make
解决方案:
在Nginx的源码中 src/http/ngx_http_upstream.h,找到 ngx_http_upstream_srv_conf_s ,在模块中添加添加default_port属性
struct ngx_http_upstream_srv_conf_s { ngx_http_upstream_peer_t peer; void **srv_conf; ngx_array_t *servers; /* ngx_http_upstream_server_t */ ngx_uint_t flags; ngx_str_t host; u_char *file_name; ngx_uint_t line; in_port_t port; in_port_t default_port; ngx_uint_t no_port; /* unsigned no_port:1 */ #if (NGX_HTTP_UPSTREAM_ZONE) ngx_shm_zone_t *shm_zone; #endif };
fair 配置
upstream myweb {
server 127.0.0.1:9091;
server 127.0.0.1:9092;
server 127.0.0.1:9093;
fair;
}
server {
listen 80;
server_name localhost;
location /proxy/ {
proxy_pass http://myweb/web/;
}
...
}
6. url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务 器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的 服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时 间的浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取。按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
upstream myweb {
hash $request_uri;
server 127.0.0.1:9091;
server 127.0.0.1:9092;
server 127.0.0.1:9093;
}
server {
listen 80;
server_name localhost;
location /proxy/ {
proxy_pass http://myweb/web/;
}
.....
}
发送10次请求访问地址:http://www.test-nginx.com/proxy/hello,输出如下:
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
hello,I am server A !
负载均衡的server中常见配置
upstream myweb {
ip_hash;
server 127.0.0.1:9091;
server 127.0.0.1:9092 down; (down 表示当前的server暂时不参与负载)
server 127.0.0.1:9093 weight=2; (weight 默认为1.weight越大,负载的权重就越大)
server 127.0.0.1:9094 backup; (其它所有的非backup机器down或者忙的时候,请求backup机器)
}
我们配置serverC端口为备份服务器,当serverA 和 serverB 都挂掉后 会自动使用备份服务器server C(9093端口),但当主服务器serverA 或serverB又启动后,在继续使用主服务器serverA 或serverB,nginx.conf配置如下:
upstream myweb {
server 127.0.0.1:9091;
server 127.0.0.1:9092;
server 127.0.0.1:9093 backup;
}
server {
listen 80;
server_name localhost;
location /proxy/{
proxy_pass http://myweb/web/;
}
访问地址:http://www.test-nginx.com/proxy/hello 10次输出结果如下,从中可以看出请求未访问到serveC (server 127.0.0.1:9093)。
hello,I am server A !
hello,I am server B !
hello,I am server A !
hello,I am server B !
hello,I am server A !
hello,I am server B !
hello,I am server A !
hello,I am server B !
hello,I am server A !
hello,I am server B !
主动停掉server A(9091端口),再次发送10次请求,10次输出结果如下:
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
再主动停掉serverB(9092端口),再次发送10次请求,10次输出结果如下,主服务器serverA和serverB均已宕机,客户端请求都访问到备份服务器serverC。
hello,I am server C !
hello,I am server C !
hello,I am server C !
hello,I am server C !
hello,I am server C !
hello,I am server C !
hello,I am server C !
hello,I am server C !
hello,I am server C !
hello,I am server C !
启动主服务器 serverB后,再次发送10次请求,10次输出结果如下,主服务器serverB已启动,客户端请求会优选访问主服务器,所以请求都会访问到主服务器serverB。
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
hello,I am server B !
在Nginx中配置proxy_pass代理转发时,如果在proxy_pass后面的url加/,表示绝对根路径;如果没有/,表示相对路径,把匹配的路径部分也给代理走。
假设下面四种情况分别用 http://127.0.0.1/proxy/hello 进行访问。
@RestController
public class HelloController {
@GetMapping({"/web/hello", "webhello"})
public String hello() {
return "hello,I am server A!";
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。