您现在的位置是:首页 >技术交流 >Nginx反向代理与负载均衡网站首页技术交流
Nginx反向代理与负载均衡
目录
一、Nginx 代理
代理是在服务器和客户端之间假设的一层服务器,代理将接收客户端的请求并将它转发给服务器,然后将服务端的响应转发给客户端。
不管是正向代理还是反向代理,实现的都是上面的功能。
1、正向代理
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
正向代理是为我们服务的,即为客户端服务的,客户端可以根据正向代理访问到它本身无法访问到的服务器资源。
正向代理对我们是透明的,对服务端是非透明的,即服务端并不知道自己收到的是来自代理的访问还是来自真实客户端的访问。
2、反向代理
反向代理*(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
反向代理是为服务端服务的,反向代理可以帮助服务器接收来自客户端的请求,帮助服务器做请求转发,负载均衡等。
反向代理对服务端是透明的,对我们是非透明的,即我们并不知道自己访问的是代理服务器,而服务器知道反向代理在为他服务。
反向代理的优势:
- 隐藏真实服务器;
- 负载均衡便于横向扩充后端动态服务;
- 动静分离,提升系统健壮性;
nginx支持哪些类型的反向代理?
- 基于七层的http/https/mail等应用协议的代理
- 基于四层的ip+tcp/udp端口的代理
二、动静分离
动静分离是指在 web 服务器架构中,将静态页面与动态页面或者静态内容接口和动态内容接口分开不同系统访问的架构设计方法,进而提示整个服务的访问性和可维护性。
一般来说,都需要将动态资源和静态资源分开,由于 Nginx 的高并发和静态资源缓存等特性,经常将静态资源部署在 Nginx 上。如果请求的是静态资源,直接到静态资源目录获取资源,如果是动态资源的请求,则利用反向代理的原理,把请求转发给对应后台应用去处理,从而实现动静分离。
使用前后端分离后,可以很大程度提升静态资源的访问速度,即使动态服务不可用,静态资源的访问也不会受到影响。
三、负载均衡
一般情况下,客户端发送多个请求到服务器,服务器处理请求,其中一部分可能要操作一些资源比如数据库、静态资源等,服务器处理完毕后,再将结果返回给客户端。
这种模式对于早期的系统来说,功能要求不复杂,且并发请求相对较少的情况下还能胜任,成本也低。随着信息数量不断增长,访问量和数据量飞速增长,以及系统业务复杂度持续增加,这种做法已无法满足要求,并发量特别大时,服务器容易崩。
很明显这是由于服务器性能的瓶颈造成的问题,除了堆机器之外,最重要的做法就是负载均衡。
请求爆发式增长的情况下,单个机器性能再强劲也无法满足要求了,这个时候集群的概念产生了,单个服务器解决不了的问题,可以使用多个服务器,然后将请求分发到各个服务器上,将负载分发到不同的服务器,这就是负载均衡,核心是「分摊压力」。 Nginx 实现负载均衡,一般来说指的是将请求转发给服务器集群。
举个具体的例子,晚高峰乘坐地铁的时候,入站口经常会有地铁工作人员大喇叭“请走 B 口, B 口人少车空…”,这个工作人员的作用就是负载均衡。
Nginx 实现负载均衡的策略
轮询策略(rr):默认情况下采用的策略,将所有客户端请求轮询分配给服务端。这种策略是可以正常工作的,但是如果其中某一台服务器压力太大,出现延迟,会影响所有分配在这台服务器下的用户。
最小连接数策略:将请求优先分配给压力较小的服务器,它可以平衡每个队列的长度,并避免向压力大的服务器添加更多的请求。
最快响应时间策略:优先分配给响应时间最短的服务器。
客户端 ip 绑定策略:来自同一个 ip 的请求永远只分配一台服务器,有效解决了动态网页存在的 session 共享问题。
四、Nginx 实战配置
Nginx 服务器:192.168.154.13:80
Tomcat服务器1:192.168.154.12:8080
Tomcat服务器2:192.168.154.10:8080 192.168.154.10:8081
根据之前Tomcat部署及优化章节下的Tomcat多实例部署,已经配置好了两个Tomcat服务器,分别是http://192.168.154.10:8080和 htttp://192.168.154.10:8081,现在我们再开一台IP地址为192.168.154.12的主机部署Tomcat 服务器。
部署Tomcat服务器前要先配置JDK环境变量
1、关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
setenforce 0
2、设置JDK环境变量
## 192.168.154.12的主机
cd /opt
tar xf jdk-8u91-linux-x64.tar.gz
mv jdk1.8.0_91/ /usr/local/
cd /usr/local/
#进入IP地址为192.168.154.10的主机,将其环境变量jdk.sh复制到192.168.154.12主机下
cd /etc/profile.d/
ls
scp jdk.sh 192.168.154.12:`pwd`
##192.168.154.12的主机
cd /etc/profile.d/
ls #可以看到jdk.sh已经复制过来了
vim jdk.sh #修改路径
export JAVA_HOME=/usr/local/jdk1.8.0_91
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
source jdk.sh
java -version
3、安装启动Tomcat
#192.168.154.12
cd /opt
tar xf apache-tomcat-8.5.16.tar.gz
mv apache-tomcat-8.5.16 /usr/local/tomcat
cd /usr/local/tomcat/bin/
./startup.sh
4、安装启动 Nginx 服务器
我们现在再开一台IP为192.168.154.13的主机来部署Nginx服务器
部署 Nginx 服务器做负载均衡
#关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
mount /dev/cdrom /mnt
yum -y install pcre-devel zlib-devel openssl-devel gcc gcc-c++ make #安装依赖包
cd /opt
tar zxvf nginx-1.12.0.tar.gz
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-file-aio --with-http_stub_status_module
make && make install
vim /lib/systemd/system/nginx.service
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx
ExecrReload=/bin/kill -s HUP $MAINPID
ExecrStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
chmod 754 /lib/systemd/system/nginx.service
systemctl daemon-reload
systemctl start nginx.service
systemctl enable nginx.service
给每个tomcat服务器添加动态网页
#192.168.154.10 添加第1个动态页面
cd /usr/local/tomcat/webapps/
mkdir test
cd test/
vim index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test1 page</title> #指定为 test1 页面
</head>
<body>
<% out.println("动态页面 1,http://www.test1.com");%>
</body>
</html>
#192.168.154.10 添加第2个动态页面
cd /usr/local/tomcat2/webapps/
mkdir test
cd test/
vim index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test2 page</title> #指定为 test2 页面
</head>
<body>
<% out.println("动态页面 2,http://www.test2.com");%>
</body>
</html>
#192.168.154.12 添加第3个动态页面
cd /usr/local/tomcat/webapps/
mkdir test
cd test/
vim index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test3 page</title> #指定为 test3 页面
</head>
<body>
<% out.println("动态页面 3,http://www.test2.com");%>
</body>
</html>
然后在Nginx服务器添加静态网页
#192.168.154.13
cd /usr/local/nginx/html
vim game.html
<html>
<body>
<h1>this is static test web!</h1>
<img src="game.jpg" /> #html/准备好的game.jpg图片
</body>
</html>
以IP为192.168.154.11的主机为客户端做网页测试
动态页面测试
静态页面测试
5、Nginx server 配置
配置nginx.conf,添加location静态页面处理及添加upstream配置段与proxy_pass
#192.168.154.13
vim /usr/local/nginx/conf/nginx.conf
#插入一下内容
...
#定义tomcat服务器组集群
upstream tomcat_servers {
server 192.168.154.10:8080 weight=1;
server 192.168.154.10:8081 weight=1;
server 192.168.154.12:8080 weight=1;
}
...
location ~* .*.jsp$ {
#将以.jsp为结尾
proxy_pass http://tomcat_servers;
#用于后端服务器获取真实的客户端IP地址
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...
##设置后端的Web服务器可以获取远程客户端的真实IP
##设定后端的Web服务器接收到的请求访问的主机名(域名或IP、端口),默认HOST的值为proxy_pass指令设置的主机名。如果反向代理服务器不重写该请求头的话,那么后端真实服务器在处理时会认为所有的请求都来自反向代理服务器,如果后端有防攻击策略的话,那么机器就被封掉了。
proxy_set_header HOST $host;
##把$remote_addr赋值给X-Real-IP,来获取源IP
proxy_set_header X-Real-IP $remote_addr;
##在nginx 作为代理服务器时,设置的IP列表,会把经过的机器ip,代理机器ip都记录下来
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
/usr/local/nginx/sbin/nginx -t
systemctl restart nginx.service
客户端192.168.154.11去访问192.168.154.13的Nginx服务器
测试负载均衡、动静分离效果
五、Nginx 负载均衡模式:
-
rr 轮询 负载均衡模式:
每个请求按时间顺序逐一分配到不同的后端服务器,如果超过了最大失败次数后(max_fails,默认1),在失效时间内(fail_timeout,默认10秒),该节点失效权重变为0,超过失效时间后,则恢复正常,或者全部节点都为down后,那么将所有节点都恢复为有效继续探测,一般来说rr可以根据权重来进行均匀分配。 -
least_conn 最少连接:
优先将客户端请求调度到当前连接最少的服务器。 -
ip_hash 负载均衡模式:
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题,但是ip_hash会造成负载不均,有的服务请求接受多,有的服务请求接受少,所以不建议采用ip_hash模式,session 共享问题可用后端服务的 session 共享代替 nginx 的 ip_hash(使用后端服务器自身通过相关机制保持session同步)。 -
fair(第三方)负载均衡模式:
按后端服务器的响应时间来分配请求,响应时间短的优先分配。 -
url_hash(第三方)负载均衡模式:
基于用户请求的uri做hash。和ip_hash算法类似,是对每个请求按url的hash结果分配,使每个URL定向到同一个后端服务器,但是也会造成分配不均的问题,这种模式后端服务器为缓存时比较好。
六、Cookie和Session的区别
Cookie 是客户端保存用户信息的一种机制,用来记录用户的一些信息。如何识别特定的客户呢?cookie 就可以做到。每次 HTTP 请求时,客户端都会发送相应的 Cookie 信息到服务端。它的过期时间可以任意设置,如果你不主动清除它,在很长一段时间里面都可以保留着,即便这之间你把电脑关机了。
Session 是在无状态的 HTTP 协议下,服务端记录用户状态时用于标识具体用户的机制。它是在服务端保存的用来跟踪用户的状态的数据结构,可以保存在文件、数据库或者集群中。在浏览器关闭后这次的 Session 就消失了,下次打开就不再拥有这个 Session。其实并不是 Session 消失了,而是 Session ID 变了,服务器端可能还是存着你上次的 Session ID 及其 Session 信息,只是他们是无主状态,也许一段时间后会被删除。
1、Cookie 在客户端(浏览器),Session 在服务器端。
2、Cookie 的安全性一般,他人可通过分析存放在本地的 Cookie 并进行 Cookie 欺骗。在安全性第一的前提下,选择 Session 更优。重要交互信息比如权限等就要放在 Session 中,一般的信息记录放 Cookie 就好了。
3、单个 Cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 Cookie。
4、Session 可以放在 文件、数据库或内存中,比如在使用 Node 时将 Session 保存在 redis 中。由于一定时间内它是保存在服务器上的,当访问增多时,会较大地占用服务器的性能。考虑到减轻服务器性能方面,应当适时使用 Cookie。
5、Session 的运行依赖 Session ID,而 Session ID 是存在 Cookie 中的,也就是说,如果浏览器禁用了 Cookie,Session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 Session ID)。
6、用户验证这种场合一般会用 Session。因此,维持一个会话的核心就是客户端的唯一标识,即 Session ID。
七、部署四层反向代理
四层代理默认情况下Nginx是不支持的,需要在安装Nginx的时候,手动去添加 stream 模块(–with-stream),该模块是开启TCP/UDP转发的模块。
下面我们对192.168.154.13的Nginx服务器重新安装编译Nginx
cd /opt/nginx-1.22.0/
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-stream #添加stream模块
make && make install
ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
nginx -V #查看stream模块是否被添加
mv nginx.conf nginx.conf.bak
cp nginx.conf.default nginx.conf
vim /usr/local/nginx/conf/nginx.conf
stream {
upstream appserver {
server 192.168.154.10:8080;
server 192.168.154.10:8081;
server 192.168.154.12:8080;
}
server {
listen 8080;
proxy_pass appserver;
}
}
为了效果,这里将长连接设为0
http://192.168.154.13:8080/test/index.jsp 测试结果 隔30s刷新一下页面
八、四层代理+七层代理
四层反向代理一般用作网关,做负载均衡,用来接收用户请求用的
七层反向代理做来做动静分离,处理静态页面
192.168.154.13 做四层反向代理实现负载均衡
192.168.154.11和 192.168.154.14 给两个web服务器做动静分离(七层反向代理)
192.168.154.10:8080 、192.168.154.10:8081 、 192.168.154.12:8080 为三台tomcat服务器
由于上面已经部署好三台tomcat服务器,这里只需要部署四层反向代理和七层反向代理即可
#192.168.154.13 做四层反向代理实现负载均衡
#跟前面步骤一样加载了 stream 模块
vim /usr/local/nginx/conf/nginx.conf
...
stream {
upstream web_server{
server 192.168.154.11:80;
server 192.168.154.14:80;
}
server {
listen 80;
proxy_pass web_server;
}
}
...
nginx -t
systemctl restart nginx
#192.168.154.11和 192.168.154.14 同时部署Nginx做七层反向代理
#要先关闭防火墙
cd /etc/yum.repos.d/ #导入nginx.repo
yum -y install nginx #使用Yum安装
nginx -V #查看是否加载stream模块
cd /etc/nginx/
cd conf.d/
vim default.conf
upstream tomcat_server {
server 192.168.154.10:8080;
server 192.168.154.10:8081;
server 192.168.154.12:8080;
}
...
location ~* .*.jsp$ {
proxy_pass http://tomcat_server;
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...
nginx -t
systemctl restart nginx
#192.168.154.11 制作网页页面
cd /usr/share/nginx/html/
mkdir test
echo '<h1>this is nginx1 test web!</h1>' > test/test.html
#192.168.154.14 制作网页页面
cd /usr/share/nginx/html/
mkdir test
echo '<h1>this is nginx2 test web!</h1>' > test/test.html
测试结果
http://192.168.154.13/test/test.html 测试负载均衡
http://192.168.154.14/test/index.jsp 测试动静分离