在上一篇笔记中我们简单的了解了Nginx的基本知识,也动手搭建了我们的第一台Nginx服务器,并且实现了反向代理功能。那么今天我们继续来探究一下Nginx的另一个功能——负载均衡。话不多说,赶紧进入正题。
今日目标如下:
1. 了解负载均衡基本含义;
2. 动手搭建Nginx负载均衡;
3. 使用Consul+upsync+Nginx实现动态负载均衡
0x01 负载均衡基本概念
- 官方表述什么是负载均衡(摘自百度百科)
- 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
- 负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
- 白话文描述什么是负载均衡
- 每当一个请求过来时,首先会请求负载均衡服务器,然后负载均衡服务器通过一些算法(轮询、ip绑定、权重等)来确定去到哪台真实服务器,当然真实服务器需要构成一个集群,这样才算真正的负载均衡。
- 负载均衡的目的:
- 减轻服务器压力。这个很明显就可以看出。没做负载均衡之前,所有的请求都压在一台服务器上。请求量一多,服务器自然而然就会挂,但是做了负载均衡后,减轻了压力,不同的请求,分发到不同的服务器上,并且如果集群中有台服务器挂了也不会影响整个系统的运行。
- 负载均衡带来的问题:
- 要做负载均衡,真实服务器肯定要构成一个集群,其实与其说是负载均衡带来的问题,还不如说是集群带来的一些分布式的问题。
- session一致性问题
- 分布式事务问题
- 分布式锁等问题
- 要做负载均衡,真实服务器肯定要构成一个集群,其实与其说是负载均衡带来的问题,还不如说是集群带来的一些分布式的问题。
- 什么是7层负载均衡?
- 首先谈下OSI 7层网络模型。图如下:
- 如图所示,从下到上,依次是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。这些都是网络的基本概念,在这里我就不多说,反正当时背这个背的要死。
- 有了上面这张图,我们来说说7层负载均衡。
- 这里的7层,不是指做了7层的负载均衡。而是基于OSI模型的应用层所做的负载均衡。是基于URL或者HTTP协议实现的。也就是基于Web请求,比较常见的就是Nginx的负载均衡
- 既然有了7层负载均衡,那么是不是还有其他层的负载均衡?答案是有的。比如4层复杂均衡。
- 四层负载均衡,就是根据请求的ip+端口,根据设定的规则,将请求转发到后端对应的IP+端口上。即基于IP+端口的负载均衡。比较常见的就是LVS。但是Nginx在1.9.0之后,加了个stream模块用于实现4层负载均衡。
- 那么最后一个问题。4层和7层负载均衡区别是什么?
- 四层负载均衡,在网络模型中的传输层中,基于主要是基于tcp协议报文实现负载均衡(比如LVS、haproxy就是四层负载均衡器),使用改写报文的源地址和目的地址。
- 七层负载均衡,在网络模型中应用层中,基于URL或者HTTP协议实现负载均衡,Web服务器。
- 首先谈下OSI 7层网络模型。图如下:
0x02 搭建Nginx负载均衡
-
upstream块配置负载均衡用法
- upstream块用于配置负载均衡。配置方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16upstream backServer{
server 192.168.25.201:8080;
server 192.168.25.202:8080;
}
#在server块里只需如下方式使用
server{
#监听80端口
listen 80;
server_name www.zyzling.top;
location / {
#在proxy_pass中指定upstream服务器(上游服务器)
proxy_pass http://backServer;
index index.html index.htm;
}
} -
使用upstream搭建负载均衡
- 说明:
- web服务器使用tomcat,两个java项目,部署在不同的tomcat上,其中只有一个页面,模拟两台服务器
- nginx在虚拟机中。在物理机访问虚拟机,然后虚拟机再通过负载均衡器访问到两台不同的java项目。
- 172.16.53.131:8080/test1/test1.html页面如下:
- 172.16.53.131:8081/test1/test1.html页面如下:
- 目标效果:通过访问www.zyzling.top,每次都访问到不同的服务器。比如第一次是访问到test1,第二次访问到test2,第三次又访问到test1如此反复。
- nginx配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36worker_processes 1;
events {
worker_connections 1024;
}
http {
##配置上游服务器 名称为zyzlingServer
upstream zyzlingServer{
server 172.16.53.131:8080;
server 172.16.53.131:8081;
}
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
#监听80端口
listen 80;
#匹配www.zyzling.top这个域名
server_name www.zyzling.top;
#www.zyzling.top下面的所有请求
location / {
# 转发到上游服务器。
proxy_pass http://zyzlingServer/;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
} - 效果如下:
- 第一次访问
- 第二次访问
- 可见,默认采用的负载均衡算法是轮询
- 第一次访问
- 说明:
-
负载均衡算法演示
-
轮询(默认采用的负载均衡算法)
- 轮询的意识就是在upstream中配置的每台服务器都会按顺序循环被访问。效果在上面也演示了。如果不配置负载均衡算法,默认就是它了。
-
权重
- 权重指的是在配置的upstream server后面加上访问这台服务器的权重。一般权重越大,访问该服务器的次数也就越多。
- 配置方式:
1
2
3
4upstream zyzlingServer{
server 172.16.53.131:8080 weight=1;
server 172.16.53.131:8081 weight=2;
}- 如上配置,8081端口的权重比8080端口大,所以请求的时候,访问8081端口的次数比8080端口的次数多。
-
ip绑定(ip_hash)
- 按字面意识理解,即它会把同一个ip的访客,绑定到一台服务器上,也就是说,如果你请求到的服务器是8080端口,在后续不管你怎么访问,在正常情况下,你永远访问的是8080端口这台服务器,因为你用的ip是一样的。其内部是按请求的ip进行hash结果分配。这种方式就可以解决分布式的Session共享问题。
- 配置方式:
1
2
3
4
5upstream zyzlingServer{
server 172.16.53.131:8080;
server 172.16.53.131:8081;
ip_hash; ##在server下面写上ip_hash;即可
}
-
0x03 Nginx动态负载均衡原理及搭建
- 动态负载均衡思路
- 什么是动态负载均衡?
- 如果不考虑动态负载均衡,我们之前每增加一台upstream server节点,或者修改权重,都要执行一次
nginx -s reload
去重新加载下配置文件,但是在这加载的过程中会断开所有的连接,其实也相当于先stop,然后在start,这样对线上用户当然体验不美好。而动态负载均衡的意思就是去动态修改upstream中的内容,却不需要重启服务器,配置就可以即时生效。
- 如果不考虑动态负载均衡,我们之前每增加一台upstream server节点,或者修改权重,都要执行一次
- consul+upsync+nginx动态负载均衡实现思路
- 使用consul作为我们存放我们配置的db,至于什么是consul,下面会简单介绍下。
- 使用Nginx的第三方upsync模块,每隔一段时间去consul上面拉取我们配置的信息,动态更新Nginx配置。
- 大致原理图如下:
- 什么是动态负载均衡?
- Consul简介
- Consul是一个分布式服务注册发现中心,类似于Zookeeper。Consul通过HTTP API来实现服务注册、发现。具体等后面学习到SpringCloud的时候再详细介绍下。
- consul启动命令解释
- 先来一段命令
./consul agent -dev -ui -node=consul-dev -client=0.0.0.0
- consul:启动consul
- agent:agent指令是consul的核心,它运行agent来维护成员的重要信息、运行检查、服务宣布、查询处理等等。
- -dev:代表以dev模式启动,该模式kv存储不会持久化存储,全在内存中(重启consul就丢了!)
- -ui:启动consul自带的web界面
- -node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
- -client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
- 先来一段命令
- consul启动后,访问
ip:8500
,我这里是访问192.168.25.201:8500
.web页面效果:
- consul对KV操作的HTTP API。官方文档地址:Consul官方文档
- 添加、更新KV
- url:
v1/kv/{key}
- method:PUT
- head:Content-Type=application/json
- url:
- 获取单个KV
- url:
v1/kv/{key}
- method:GET
- url:
- 获取该分类下所有KV
- url:
v1/kv/{key}?recurse
- url:
- 添加、更新KV
- upsync简介
- upSync是新浪开发的一个Nginx第三方模块,用于从Consul上拉取配置文件,并动态更新Nginx的路由信息,upSync模块支持修改的属性有:weight、max_fails、fail_timeout、down。
- weight:设置权重
- max_fails:可以发生错误的最大次数
- fail_timeout:在fail_timeout设定的时间内与后端服务器通信失败的次数超过max_fails设定的次数,则认为这个服务器不在起作用;在接下来的 fail_timeout时间内,nginx不再将请求分发给失效的server
- down:如果需要临时移除某台服务器,可以把服务器的down置为1.相反,为0就代表可用。
- upSync是新浪开发的一个Nginx第三方模块,用于从Consul上拉取配置文件,并动态更新Nginx的路由信息,upSync模块支持修改的属性有:weight、max_fails、fail_timeout、down。
- 使用Consul+Upsync+Nginx搭建动态负载均衡
- 下载consul。这里我们使用consul的版本为1.5.1 Linux命令如下:
wget https://releases.hashicorp.com/consul/1.5.1/consul_1.5.1_linux_amd64.zip
- 下载upsync。upsync在github上开源,所以需要到github上下载最新版(master)。Linux命令如下:
wget https://github.com/weibocom/nginx-upsync-module/archive/master.zip
- 下载Nginx。注意,这里的Nginx版本要在1.9.0以上
- 使用unzip命令解压consul(如果找不到unzip命令,则使用yum install unzip安装下)。
- 执行
./consul
命令确保可以运行。出现如下界面说明consul已经没有问题;
- 使用unzip解压upsync
- 解压Nginx
- 添加Nginx用户和组
- groupadd nginx
- useradd -g nginx -s /sbin/nologin nginx
- mkdir -p /var/tmp/nginx/client/
- mkdir -p /usr/local/nginx
- 如果没有执行上面的命令。在启动Nginx的时候会报如下错误:
- 编译Nginx并安装。
- 执行./configure命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16./configure
--prefix=/usr/local/nginx
--user=nginx
--group=root
--with-http_ssl_module
--with-http_flv_module
--with-http_stub_status_module
--with-http_gzip_static_module
--with-http_realip_module
--http-client-body-temp-path=/var/tmp/nginx/client/
--http-proxy-temp-path=/var/tmp/nginx/proxy/
--http-fastcgi-temp-path=/var/tmp/nginx/fcgi/
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi
--http-scgi-temp-path=/var/tmp/nginx/scgi
--with-pcre
--add-module=../nginx-upsync-module-master - 执行
make && make install
安装Nignx
- 执行./configure命令。
- 配置Nginx。配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
upstream zyzlingServer {
#使用upsync指定consul中拉取kv的地址。
#upsync_timeout表示从consul拉取配置的超时时间
#upsync_interval表示每隔500ms就去consul中获取一次
#strong_dependency配置nginx在启动时是否强制依赖配置服务器,如果配置为on,则拉取配置失败时nginx启动同样失败
upsync 192.168.25.201:8500/v1/kv/zyzling/ upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
# upsync_dump_path,指定从consul拉取的上游服务器后持久化到的位置,这样即使consul服务器出问题了,本地还有一个备份。
upsync_dump_path /usr/local/nginx/conf/servers/servers_dump.conf;
}
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name www.zyzling.top;
location / {
proxy_pass http://zyzlingServer/;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
} - 创建upsync_dump_path。
mkdir -p /usr/local/nginx/conf/servers
- 启动consul,启动命令如下:
./consul agent -dev -ui -node=consul-dev -client=0.0.0.0
- 使用postman调用Consul的http API。putKV键值对。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16url:http://192.168.25.201:8500/v1/kv/zyzling/172.16.53.131:8080
param:
{
"weight":2,
"max_fails":2,
"fail_timeout":10,
"down":0
}
url:http://192.168.25.201:8500/v1/kv/zyzling/172.16.53.131:8081
param:
{
"weight":1,
"max_fails":2,
"fail_timeout":10,
"down":0
}- 执行后,到consul的web界面的看看效果。
- 发现如果Consul帮我们分类了。点进去如下:
- 再点进去,就是我们设置的值了。如下:
- 发现如果Consul帮我们分类了。点进去如下:
- 执行后,到consul的web界面的看看效果。
- 启动我们的Nginx。看看效果。
- 下载consul。这里我们使用consul的版本为1.5.1 Linux命令如下:
- 结果演示
- 根据我们的负载均衡权重配置,8080端口(test1)的这台服务器的权重要比8081(test2)的大。所以访问8080端口的次数会多一些.
- 使用postman请求consul,删除8081(test2)节点。看看效果怎样。
- 请求:
http://192.168.25.201:8500/v1/kv/zyzling/172.16.53.131:8081
- method:DELETE
- 结果:
- 结果所有的请求都只会请求到8080端口(test1)上。
- 请求:
0x04 参考资料
评论