(014)Nginx静态资源web服务_负载均衡
1、负载均衡简介
负载均衡可以缓解单台服务的压力,防止单点故障。负载均衡按照范围分为GSLB和SLB,区别是影响范围不同。GSLB是一个全局负载均衡,节点庞大,地域范围广,往往以国家、省地区为单位进行全局负载均衡。如图:
GSLB由调度中心节点、边缘调度节点、应用服务中心节点、应用服务节点组成。不可能所有访问都去请求中心节点,而是先去请求调度节点。比如张三在北京,先去请求调度节点,调度节点返回给张三对应的地址,张三根据地址请求对应的应用服务。调度节点由调度中心节点控制。
往往接触最多的是SLB:调度节点和服务节点在一个服务单元或一个地域里面。请求过来给调度节点,调度节点转发给服务节点,服务节点响应给客户。如图:
SLB按照网络OSI模型分为:四层负载均衡和七层负载均衡。
四层负载均衡在OSI模型中的传输层,传输层支持到TCP/IP协议的控制,它只需对客户端请求进行TCP/IP的包转发就可以实现负载均衡,好处是性能快,只需要最底层进行应用处理,而不需要进行复杂的逻辑,只需要进行包的转发。
七层负载均衡在OSI模型中的应用层,可以完成许多应用方面协议的请求。比如HTTP的应用层负载均衡:实现HTTP信息的改写、头信息的改写、安全应用规则的控制以及转发、 Rewrite等规则,Nginx是一个典型的七层负载均衡的SLB。
2、配置语法
Nginx负载均衡用到了proxy_pass,它把所有客户端的请求转发到后端的服务器上,只是不是转发到一台服务器,而是一组虚拟的服务池,称为upstream server,它里面可以定义很多服务。当请求过来会通过upstream server分发到不同的服务上,实现负载均衡。语法如下:
Syntax:upstream name {...};
Default:-
Context:http
大括号中可以是域名、域名:端口、域名:端口 参数等,如下:
upstream backend{
server backend1.example.com weight=5;#权重
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;#备份节点
server backup2.example.com:8080 backup;
}
参数及其含义:
down:当前的server暂时不参与负载均衡。
backup:预留的备份服务器,当其它节点不存活了,再启动。
max_fails:允许请求失败的次数,当请求失败的次数用完了就不在尝试,休息,执行fail_timeout。
fail_timeout:经过max_fails失败后,服务暂停的时间。
max_conns:限制最大的接收的连接数,节点性能不一致时配置。
3、Nginx的调度算法
轮询(默认):按时间顺序逐一分配到不同的后端服务器。
加权轮询:weight值越大,分配到的访问几率越高。
ip_hash:每个请求按访问IP的hash结果分配,这样来自同一个IP的固定访问一个后端服务器。
url_hash:按照访问的URL的hash结果来分配请求,是每个URL定向到同一个后端服务器。
least_conn:最少连接数,哪个机器连接数少就分发。
hash关键数值:hash自定义的key。
ip_hash缺陷:如果前端再走一层代理,那么取到的remote_addr就不是用户真实的IP。
4、示例
准备两台虚拟机151和152。151上配置Nginx负载均衡,152上由Nginx配置3个不同端口提供服务。
在152上新建/opt/app/code1/index.html;opt/app/code2/index.html;opt/app/code3/index.html;内容分别为:
<html> <head> <meta charset="utf-8"> <title>server1</title> </head> <body style="background-color:yellow;"> <h1>Server 1<h1> </body> </html>
<html> <head> <meta charset="utf-8"> <title>server2</title> </head> <body style="background-color:red;"> <h1>Server 2<h1> </body> </html>
<html> <head> <meta charset="utf-8"> <title>server3</title> </head> <body style="background-color:yellow;"> <h1>Server 3<h1> </body> </html>
在152的/etc/nginx/conf.d中新建server1.conf、server2.conf、server3.conf,分别指定端口和首页路径
server { listen 8001; server_name localhost; access_log /var/log/nginx/server1.access.log main; location / { root /opt/app/code1; index index.html index.htm; }
... ... }
server { listen 8002; server_name localhost; access_log /var/log/nginx/server2.access.log main; location / { root /opt/app/code2; index index.html index.htm; }
... ... }
server { listen 8003; server_name localhost; access_log /var/log/nginx/server3.access.log main; location / { root /opt/app/code3; index index.html index.htm; }
... ... }
在151的/etc/nginx/conf.d中新建upstream_test.conf,其中myLoad是定义的负载名字
upstream myLoad { server 192.168.7.152:8001; server 192.168.7.152:8002; server 192.168.7.152:8003; } server { listen 80; server_name localhost; access_log /var/log/nginx/test_upstream.access.log main; resolver 8.8.8.8; location / { proxy_pass http://myLoad; include proxy_params; }
... ... }
1)演示轮询和某节点宕机后依然能正常访问
启动152和151的Nginx,浏览器输入:http://192.168.7.151/,验证是轮流访问3个端口。
验证一个节点宕机,剩余的节点可以正常服务。现在用的是一台虚拟机模拟3个应用,手动禁掉8002端口:
iptables -I INPUT -p tcp --dport 8002 -j DROP
再次访问http://192.168.7.151/,验证是轮流访问8001和8003端口。清除掉临时的规则,使8002端口可以正常访问:
iptables -F
清除掉规则后,浏览器输入:http://192.168.7.151/,变成了3个端口轮流访问。
2)演示backup
重新修改151上的配置文件,负载均衡部分改为如下:
upstream myLoad { server 192.168.7.152:8001 down; server 192.168.7.152:8002 backup; server 192.168.7.152:8003 max_fails=1 fail_timeout=10s; }
重新启动Nginx,并访问http://192.168.7.151/,发现不在再轮询,只有8003能访问。使用iptables禁掉8003后发现8002顶了上来,8002可以访问。重新启用8003后,8002不可以访问了,只有8003可以访问。
3)演示加权轮询
重新修改151上的配置文件,负载均衡部分改为如下:
upstream myLoad { server 192.168.7.152:8001; server 192.168.7.152:8002 weight=5; server 192.168.7.152:8003; }
重新启动Nginx,并访问http://192.168.7.151/,发现访问7次,有5次访问的是端口8002,其它各访问了1次。
4)演示ip_hash
重新修改151上的配置文件,负载均衡部分改为如下:
upstream myLoad { ip_hash; server 192.168.7.152:8001; server 192.168.7.152:8002; server 192.168.7.152:8003; }
重新启动Nginx,并访问http://192.168.7.151/,多次刷新发现一直访问8002,因为基于$remote_addr做hash,客户端IP固定。
5)演示hash key
说明:ip_hash可以理解为hash key的变体,ip_hash是固定的ip访问同一台服务器,hash key是固定的key访问同一台服务器。在实际工作中,我们会遇到这种情况,浏览器请求一个url,访问的是服务器1,服务器1缓存了一部分内容,浏览器又请求了一遍该url,访问的是服务器2,服务器2又缓存了一部分内容,这两部分内容可能不一致,这样浏览器访问同一个url可能会出现不一致的结果。原则上使用ip_hash可以解决,但是往往无法取到客户端的ip。这时可以使hash key实现。语法如下:
Syntax:hash key [consistent];
Default:-
Context:upstream
This directive appeared in version 1.7.2.(该版本后推出)
下面演示一下hash $request_uri,请求的是同一个url的时候就定位到同一台服务器上。
在152上的/opt/app/code1、code2、code3中分别新建url1.html、url2.html、url3.html共9个文件,内容分别为:
<html> <head> <meta charset="utf-8"> <title>server1</title> </head> <body style="background-color:yellow;"> <h1>Server 1 url 1<h1> </body> </html>
其余8个html文件基本类似,修改一下背景色和显示内容即可
code1/url2.html:背景色yellow,显示内容Server 1 url 2 code1/url3.html:背景色yellow,显示内容Server 1 url 3 code2/url1.html:背景色red, 显示内容Server 2 url 1 code2/url2.html:背景色red, 显示内容Server 2 url 2 code2/url3.html:背景色red, 显示内容Server 2 url 3 code3/url1.html:背景色blue, 显示内容Server 3 url 1 code3/url2.html:背景色blue, 显示内容Server 3 url 2 code3/url3.html:背景色blue, 显示内容Server 3 url 3
重新修改151上的配置文件,负载均衡部分改为如下:
upstream myLoad { hash $request_uri; server 192.168.7.152:8001; server 192.168.7.152:8002; server 192.168.7.152:8003; }
重新启动Nginx,并访问http://192.168.7.151/url1.html,多次刷新发现同一个url访问同一台服务器。
备注:实际url可能很长,可以根据规则,使用表达式截取后的来定位同一台服务器。hash key支持表达式。