nginx 反向代理实现负载均衡*理论

时间:2021-06-02 21:13:58

Nginx负载均衡集群介绍

负载均衡集群提供了一种廉价,有效,透明的方法,来扩展网络设备和服务器的负载,带宽和吞吐量,同时加强了网络数据处理能力,提高了网络的灵活性和可用性。

搭建负载均衡服务的需求:

(1)把单台计算机无法承受的大规模并发访问或数据流量分担到多台节点设备上,分别进行处理,减少用户等待响应的时间,提升用户体验。 
(2)单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力得到大幅度提高。 
(3)7*24小时的服务保证,任意一个或多个有限后面节点设备宕机,不能影响业务。

反向代理与负载均衡概念简介:

Nginx仅仅是作为Nginx Proxy反向代理使用的,因为这个反向代理功能表现的效果是负载均衡集群的效果,所以称之为Nginx负载均衡

反向代理接收访问用户的请求后,会代理用户重新发起请求代理下的节点服务器,最后把数据返回给客户端用户,在节点服务器看来,访问的节点服务器的客户端用户就是反向代理服务器了,而非真实的网站访问用户。Nginx反向代理是接收用户的请求然后重新发起请求去请求其后面的节点。

实现Nginx负载均衡的组件说明:

nginx 反向代理实现负载均衡*理论

搭载nginx负载均衡

实验环境:

服务器 IP 说明
lb160 192.168.50.160 主nginx负载均衡
lb162 192.168.50.162 备nginx负载均衡
nginx163 192.168.50.163 nginx服务1
nginx164 192.168.50.164 nginx服务2

nginx 反向代理实现负载均衡*理论

软件准备

系统:CentOS Linux release 7.5.1804 (Core)    (不了解CentOS7看前边CentOS7博文)

软件:nginx-1.14.0.tar.gz

安装Nginx软件

4台服务器安装Nginx

yum install -y pcre-devel openssl-devel gcc gcc-c++ make     #安装依赖包命令
useradd -s /sbin/nologin -M nginx           #创建用户        
tar xf nginx-1.14..tar.gz -C /usr/src/          #tar解压
cd /usr/src/nginx-1.14./                  
./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module ; make ; make install
ln -s /usr/local/nginx/sbin/* /usr/local/sbin/       #软连接到全局变量

Centos7 system启动nginx文件

vim /usr/lib/systemd/system/nginx.service     #创建nginx.service文件 插入下边代码
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target [Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/bin/kill -s QUIT $MAINPID
PrivateTmp=true [Install]
WantedBy=multi-user.target

将启动脚本发给其他三台服务器

scp /usr/lib/systemd/system/nginx.service root@192.168.50.162:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/nginx.service root@192.168.50.163:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/nginx.service root@192.168.50.164:/usr/lib/systemd/system/

配置用于测试的Web服务

nginx163 测试配置文件

vim /usr/local/nginx/conf/nginx.conf

worker_processes  ;
events {
worker_connections ;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout ;
log_format main '$remote_addr-$remote_user[$time_local]"$request"'
'$status $body_bytes_sent "$http_referer"'
'"$http_user_agent""$http_x_forwarded_for"';
server {
listen ;
server_name bbs.wk.com;
location / {
root html/bbs;
index index.html index.htm;
}
access_log logs/access_bbs.log main;
}
server {
listen ;
server_name www.wk.com;
location / {
root html/www;
index index.html index.htm;
}
access_log logs/access_www.log main;
}
}

#提示:

这里故意将www虚拟主机放在下面,便于用后面的参数配置测试效果

nginx -t      #检测语法

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

nginx        #启动服务

加入测试数据文件

mkdir /usr/local/nginx/html/{www,bbs}
echo "" >> /usr/local/nginx/html/www/index.html
echo "" >> /usr/local/nginx/html/bbs/index.html
开启服务后自己做测试看是否能访问

nginx164 测试配置文件

vim /usr/local/nginx/conf/nginx.conf

worker_processes  ;
events {
worker_connections ;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout ;
log_format main '$remote_addr-$remote_user[$time_local]"$request"'
'$status $body_bytes_sent "$http_referer"'
'"$http_user_agent""$http_x_forwarded_for"';
server {
listen ;
server_name www.wk.com;
location / {
root html/www;
index index.html index.htm;
}
access_log logs/access_www.log main;
}
server {
listen ;
server_name bbs.wk.com;
location / {
root html/bbs;
index index.html index.htm;
}
access_log logs/access_bbs.log main;
}
}
mkdir /usr/local/nginx/html/{www,bbs}
echo "wwwwwwwwww" >> /usr/local/nginx/html/www/index.html
echo "bbbbbbbbbb" >> /usr/local/nginx/html/bbs/index.html

提示: 
(1)不同Web测试节点,返回的结果是不同的,这是为了方便测试演示! 
(2)通过上面配置就实现了两台Web服务器基于域名的虚拟主机配置。

实现一个简单的负载均衡

配置lb160配置文件

worker_processes  ;
events {
worker_connections ;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout ;
upstream www_server_pools {       #这里定义Web服务器池,包含了163,164两个Web节点
server 192.168.50.163:80 weight=;
server 192.168.50.164:80 weight=;
}
server {                  #这里定义代理的负载均衡域名虚拟主机
listen ;
server_name www.wk.com;
location / {
proxy_pass http://www_server_pools;    #访问www.wk.com,请求发送给www_server_pools里面的节点
}
}
} #干净网页
worker_processes ;
events {
worker_connections ;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout ;
upstream www_server_pools {
server 192.168.50.163: weight=;
server 192.168.50.164: weight=;
}
server {
listen ;
server_name www.wk.com;
location / {
proxy_pass http://www_server_pools;
}
}
}

检查语法并启动并在网页上测试

hosts域名解析

nginx 反向代理实现负载均衡*理论

nginx 反向代理实现负载均衡*理论

nginx 反向代理实现负载均衡*理论

两个Web节点按照1:1的比例被访问,宕掉任意一个Web节点,网站业务不受影响,访问请求都定位到了正常的节点上

从新开启会又安1:1比例被访问

Nginx负载均衡核心组件介绍

Nginx upstream模块

Nginx upstream模块

Nginx的负载均衡功能依赖于ngx_http_upsteam_module模块,所支持的代理方式包括proxy_pass,fastcgi_pass,memcached_pass等,新版Nginx软件支持的方式有所增加。ngx_http_upstream_module模块允许Nginx定义一组或多组节点服务器组,使用时可以通过proxy_pass代理方式把网站的请求发送到事先定义好的对应Upstream组的名字上,具体写法为“proxy_pass http:// www_server_pools”,其中www_server_pools就是一个Upstream节点服务器组名字。

ngx_http_upstream_module模块官方地址为:http://nginx.org/en/docs/http/ngx_http_upstream_module.html

upstream模块语法

范例1:基本的upstream配置案例

upstream www_server_pools {
#upstream是关键字必须有,后面的www_server_pools为一个Upstream集群组的名字,可以自己起名,调用时就用这个名字
server 192.168.50.163: weight=;
server 192.168.50.164: weight=;
server 192.168.50.165: weight=;
#server关键字是固定的,后面可以接域名(门户会用)或IP。如果不指定端口,默认是80端口。weight代表权重,
数值越大被分配的请求越多,结尾有分号,别忘了。
}

范例2:较完整的upstream配置案例

upstream blog_server_pool {
server 192.168.50.163; #这行标签和下行是等价的
server 192.168.50.164: weight= max_fails= fail_timeout=10s; #这行标签和上一行是等价的,此行多余的部分就是默认配置,不写也可以。
server 192.168.50.165: weight= max_fails= fail_timeout=20s backup;
# server最后面可以加很多参数,具体参数作用看下文的表格
}

范例3:使用域名及socket的upstream配置案例   

upstream backend {
server backend1.example.com weight=;
server backend2.example.com:; #域名加端口。转发到后端的指定端口上
server unix:/tmp/backend3; #指定socket文件
#提示:server后面如果接域名,需要内网有DNS服务器或者在负载均衡器的hosts文件做域名解析。
server 192.168.50.163;
server 192.168.50.164:;
server backup1.example.com: backup;
#备份服务器,等上面指定的服务器都不可访问的时候会启动,backup的用法和Haproxy中用法一样
server backup2.example.com: backup;
}

如果是两台Web服务器做高可用,常规方案就需要keepalived配合,那么这里使用Nginx的backup参数通过负载均衡功能就可以实现Web服务器集群了,对于企业应用来说,能做集群就不做高可用。

upstream模块相关说明

upstream模块的内容应放于nginx.conf配置的http{}标签内,其默认调度节点算法是wrr(weighted round-robin,即权重轮询)。

upstream模块内参数 参数说明
server 192.168.50.163 负载均衡后面的RS配置,可以是IP或域名,如果端口不写,默认是80端口。高并发场景下,IP 可换成域名,通过DNS做负载均衡
weight=1 代表服务器的权重,默认值是1。权重数字越大表示接受的请求比例越大
max_ fails=1

Nginx尝试连接后端主机失败的次数,这个数值是配合proxy_ next_ upstream,fastcgi_ next_ upstream 和memcached_ next_ upstream
这三个参数来使用的,当Nginx接收后端服务器返回这三个参数定义的状态码时,会将这个请求转发给正常工作的后端服务器,例如404.502、 503。 Max_ fails 的默认值是1;企业场景下建议2 ~ 3次。如京东1次,蓝汛10次,根据业务需求去配置

backup

热备配置(RS节点的高可用),当前面激活的RS都失败后会自动启用热备RS。这标志着这个服务器作为备份服务器,若主服务器全部宕机了,就会向它转发请求;注意,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup

fail_timeout=10s

在max_fails定义的失败次数后,距离下次检查的间隔时间,默认是10s;如果max_ fails是5,它就检测5次, 如果5次都是502。那么,它就会根据fail_ timeout的值,等待10s再去检查,还是只检查一-次, 如果持续502,在不重新加载Nginx配置的情况“下,每隔10s都只检测一次。常规业务2 ~ 3秒比较合理,比如京东3秒,蓝汛3秒,可根据业务需求去配置

 down 

这标志着服务器永远不可用,这个参数可配合ip_ hash 使用

示例,如下:

upstream backend {
server backend1.example.com weight=; #如果就是单个Server,没必要设置权重
server 127.0.0.1: max_fail= fail_timeout=10s;
#当检测次数等于5的时候,5次连续检测失败后,间隔10s再重新检测。
server unix:/tmp/backend3;
server backup1.example.com: backup; #热备机器设置
}

需要特别说明的是,如果是Nginx代理Cache服务,可能需要使用hash算法,此时若宕机,可通过设置down参数确保客户端用户按照当前的hash算法访问,这一点很重要。示例配置如下:

upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}

下面是Haproxy负载均衡器server标签的配置示例。

#开启对后端服务器的健康检测,通过GET /test/index.php来判断后端服务器的健康情况
server php_server_1 192.168.50.163: cookie check inter rise fall weight
server php_server_2 192.168.50.164: cookie check inter rise fall weight
server php_server_bak 192.168.50.165: cookie check inter rise fall backup

上述命令的说明如下:

  • weight:调节服务器的请求分配权重。
  • check:开启对该服务器健康检查。
  • inter:设置连续两次的健康检查间隔时间,单位毫秒,默认值2000
  • rise:指定多少次连续成功的健康检查后,即可认定该服务器处于可用状态。
  • fall:指定多少次不成功的健康检查后,即认为服务器为宕机状态,默认值3.
  • maxconn:指定可被发送到该服务器的最大并发连接数。

upstream模块调度算法

调度算法一般分为两类: 
第一类为静态调度算法,即负载均衡器根据自身设定的规则进行分配,不需要考虑后端节点服务器的情况,例如:rr,wrr,ip_hash等都属于静态调度算法。 
第二类为动态调度算法,即负载均衡器会根据后端节点的当前状态来决定是否分发请求,例如:连接数少的优先获得请求,响应时间短的优先获得请求。例如:least_conn,fair等都属于动态调度算法。

常见的调度算法。

rr轮询(默认调度算法,静态调度算法)

wrr(权重轮询,静态调度算法)

ip_hash(静态调度算法)(会话保持)

每个请求按客户端IP的hash结果分配,当新的请求到达时,先将其客户端IP通过哈希算法哈希出一个值,在随后的客户端请求中,客户IP的哈希值只要相同,就会被分配至同一台服务器,该调度算法可以解决动态网页的session共享问题,但有时会导致请求分配不均,即无法保证1:1的负载均衡,因为在国内大多数公司都是NAT上网模式,多个客户端会对应一个外部IP,所以,这些客户端都会被分配到同一节点服务器,从而导致请求分配不均。LVS负载均衡的-p参数,Keepalived配置里的persistence_timeout 50参数都类似这个Nginx里的ip_hash参数,其功能都可以解决动态网页的session共享问题。

示例如下:

upstream {
ip_hash;
server 192.168.50.163:;
server 192.168.50.164:;
}
upstream backend{
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}

注意: 
当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能有weight和backup,即使有也不会生效。

fair(动态调度算法

此算法会根据后端节点服务器的响应时间来分配请求,响应时间短的优先分配。这是更加智能的调度算法。此种算法可以根据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身不支持fair调度算法,如果需要使用这种调度算法,必须下载Nginx相关模块upstream_fair。

示例如下:

upstream wk_lb{
server 192.168.50.163;
server 192.168.50.164;
fair;
}

least_conn(最小连接算法)

least_conn算法会根据后端节点的连接数来决定分配情况,哪个机器连接数少就分发。 
除了上面介绍的这些算法外,还有一些第三方调度算法,例如:url_hash,一致性hash算法等,介绍如下。

upstream wk_lb{
least_conn;
server 192.168.50.163;
server 192.168.50.164;
}

url_hash算法(web缓存节点)

与ip_hash类似,这里是根据访问URL的hash结果来分配请求的,让每个URL定向到同一个后端服务器,后端服务器为缓存服务器时效果显著。在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method使用的是hash算法。 
url_hash按访问URL的hash结果来分配请求,使每个URL定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率命令率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx的hash模块软件包。

url_hash(web缓存节点)和ip_hash(会话保持)类似。示例配置如下:

upstream wk_lb {
server squid1:;
server squid2:;
hash $request_uri;
hash_method crc32;
}

一致性hash算法

一致性hash算法一般用于代理后端业务为缓存服务(如Squid,Memcached)的场景,通过将用户请求的URI或者指定字符串进行计算,然后调度到后端的服务器上,此后任何用户查找同一个URI或者指定字符串都会被调度到这一台服务器上,因此后端的每个节点缓存的内容都是不同的,一致性hash算法可以解决后端某个或几个节点宕机后,缓存的数据动荡最小,一致性hash算法知识比较复杂,详细内容可以参考百度上的相关资料,这里仅仅给出配置示例:

http {
upstream test {
consistent_hash $request_uri;
server 127.0.0.1: id= weight=;
server 127.0.0.1: id= weight=;
server 127.0.0.1: id= weight=;
}
}

虽然Nginx本身不支持一致性hash算法,但Nginx得分支Tengine支持。详细可参考http://tengine.taobao.org/document_cn/http_upstream_consistent_hash_cn.html

http_proxy_module模块

proxy_pass指令介绍

proxy_pass指令属于ngx_http_proxy_module模块,此模块可以将请求转发到另一台服务器,在实际的反向代理工作中,会通过location功能匹配指定的URI,然后把接收到的符合匹配URI的请求通过proxy_pass抛给定义好的upstream节点池。该指令官方地址1见:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

proxy_pass的使用案例:

将匹配URI为name的请求抛给http://127.0.0.1/remote/.

location /name/ {
proxy_pass http://127.0.0.1/remote/;
}
将匹配URI为some/path的请求抛给http://127.0.0.1

location /some/path/ {
proxy_pass http://127.0.0.1;
}
将匹配URI为name的请求应用指定的rewrite规则,然后抛给http://127.0.0.1

location /name/ {
rewrite /name/( [^/]+ ) /username=$ break;
proxy_pass http://127.0.0.1;
}

http proxy模块参数

Nginx的代理功能是通过http proxy模块来实现的。默认在安装Nginx时已经安装了http proxy模块,因此可直接使用http proxy模块。下面详细解释模块1中每个选项代表的含义,见下表:

  http proxy模块相关参数  说明
proxy_ set_ header 设置http请求header项传给后端服务器节点,例如:可实现让代理后端的服务器节点获取访问客户端用户的真实IP地址
client_ body_ buffer_ size 用于指定客户喘请求主体缓冲区大小,此处如了解前文的http请求包的原理就好理解了
proxy_ connect_ timeout 表示反向代理与后端节点服务器连接的超时时间,即发起握手等候响应的超时时间
proxy_ send_ timeout 表示代理后端服务器的数据回传时间,即在规定时间之内后端服务器必须传完所有的数据,否则,Nginx将断开这个连接
proxy_ read_ timeout 设置Nginx从代理的后端服务器获取信息的时间,表示连接建立成功后,Nginx等待后端服务器的响应时间,其实是Nginx已经进人后端的排队之中等候处理的时间
proxy_ buffer_ size 设置缓冲区大小,默认该缓冲区大小等于指令proxy_ buffers 设置的大小
proxy_ buffers 设置缓冲区的数量和大小。Nginx 从代理的后端服务器获取的响应信息,会放置到缓冲区
proxy_ busy_ buffers_ size 用于设置系统很忙时可以使用的proxy_buffers大小,官方推荐的大小为proxy_ buffers*2
proxy_ temp_ file_ write_ size 指定proxy缓存临时文件的大小