Nginx反向代理和负载均衡
Nginx和Springboot相结合
我们可以通过把springboot程序直接上传到服务器上运行就可以直接访问了,因为springboot内嵌Tomcat服务器。
但是从性能上来说,Tomcat的并发量远远没有Nginx好,并且访问静态网页的加载速度上,Nginx也比Tomcat快的多,因此实际情况下,我们使用Nginx作为静态网页和最外部接收请求的服务器,而springboot只暴露API。Nginx把访问的api的请求转发到springboot上。
总结来说,就是把所有的请求直接访问到Nginx上再转发到springboot服务器,而不是像以前一样直接让外部访问springboot
这就是反向代理。
配置Nginx反向代理
我们先上传一个springboot项目写俩api,用jar包的形式,记得在服务器上装java环境,之后用screen命令让jar在后台运行在8080端口。
访问http://你的服务器地址:8800/api/port
会得到端口号信息:
访问http://你的服务器地址:8800/api/name
会得到节点名:
这样就配置成功了
1.基本的反代
location /api {
# 转发到目的服务器的/路径下
proxy_pass http://127.0.0.1:8800;
}
这个Spring Boot有两个接口:/api/port
和/api/name
,那么我们就配置一下访问Nginx下的/api
开头的路径时,都代理到这个Spring Boot上。
现在在Nginx配置文件中,找到80
端口的server
块,在里面添加一个location
块用于代理80
端口上路径为/api
开头的请求将其转发到我们的Spring Boot上:
reload一下配置
这次是访问nginx,nginx反代到springboot项目中
通过筛选所有/api的后缀的请求去转发到javaApi中
2.绝对路径和相对路径代理
location /api {
# 转发到目的服务器的/路径下
proxy_pass http://127.0.0.1:8800/;
}
还是访问上述路径,结果:
可见我们只是在上述代理的地址后面加了个/
,就变成了404,怎么差别这么大呢?
这是因为这次的反向代理地址我们不仅指定了地址还指定了路径/
* ,* 当proxy_pass
后面的地址指定了路径之后,就变成了绝对路径代理。
我们上述location
后面为/api
,proxy_pass
为http://127.0.0.1:8800/
,则表示访问服务器地址的/api/xxx
路径下时,转发请求到http://127.0.0.1/xxx
路径下。
相信大家现在明白了相对路径和绝对路径代理的区别,我这里还是放几个例子来加深理解:
# 接收来自路径/api开头的请求
location /api {
# 相对路径代理,将所有的/api/xxx的请求转发到127.0.0.1:8800/api/xxx
# 例如:
# 访问:http://服务器地址/api,则转发到:http://127.0.0.1:8800/api
# 访问:http://服务器地址/api/get,则转发到:http://127.0.0.1:8800/api/get
# 访问:http://服务器地址/api/get/1,则转发到:http://127.0.0.1:8800/api/get/1
proxy_pass http://127.0.0.1:8800;
}
# 接收来自路径/api开头的请求
location /api {
# 绝对路径代理,将所有的/api/xxx的请求转发到http://127.0.0.1:8801/xxx
# 例如:
# 访问:http://服务器地址/api,则转发到:http://127.0.0.1:8801/
# 访问:http://服务器地址/api/get,则转发到:http://127.0.0.1:8801/get
# 访问:http://服务器地址/api/get/1,则转发到:http://127.0.0.1:8801/get/1
proxy_pass http://127.0.0.1:8801/;
}
# 接收来自路径/resource开头的请求
location /resource {
# 绝对路径代理,将所有的/resource/xxx的请求转发到http://127.0.0.1:8802/static/xxx
# 例如:
# 访问:http://服务器地址/resource,则转发到:http://127.0.0.1:8802/static
# 访问:http://服务器地址/resource/get,则转发到:http://127.0.0.1:8802/static/get
# 访问:http://服务器地址/resource/get/1,则转发到:http://127.0.0.1:8802/static/get/1
proxy_pass http://127.0.0.1:8802/static;
}
nginxcopy
大家可以多看看并自己都尝试一下上述的例子,加深对相对路径和绝对路径代理的理解。
总的来说:
- 当
proxy_pass
后面仅仅指定反代地址的时候,就是相对路径代理,location
后的路径也会被追加到最终的代理地址后 - 当
proxy_pass
后面指定反代地址及其路径的时候,就是绝对路径代理,location
后的路径不会被追加到最终的代理地址后
绝大多数时候,我们使用相对路径代理即可,可以避免不必要的麻烦,但是大家还是很有必要学习两种路径模式,否则可能会踩坑。
3.Nginx负载均衡
虽然Nginx可以一次性处理众多请求,但是tomcat不行。因此我们可以用集群的方式部署多个服务。用nginx平坦请求,实现负载均衡
我们可以开3个终端跑三个java程序来模拟
# 窗口1
java -jar nginx-proxy-server.jar --spring.profiles.active=1
# 窗口2
java -jar nginx-proxy-server.jar --spring.profiles.active=2
# 窗口3
java -jar nginx-proxy-server.jar --spring.profiles.active=3
让他们模拟构成一个集群
可以在springboot配置多个配置文件,然后用spring.profiles.active=3
来触发使用哪个配置文件
在nginx中,我们可以配置一个集群
在http块中,配置
# 目的服务器集群列表,命名为myspringboot
upstream myspringboot {
# 用server指令声明每个服务器的地址
server 127.0.0.1:8800;
server 127.0.0.1:8801;
server 127.0.0.1:8802;
server 127.0.0.1:8803;
}
然后修改用于转发的location块
# 处理/api路径开头的请求
location /api {
# 转发到myspringboot服务器列表的/api路径下
proxy_pass http://myspringboot;
}
这样就能实现负载均衡了
可见我们每次虽然都是访问的是Nginx服务器,但是每一次都给我们转发到了不同的Spring Boot服务器上,这就是负载均衡的效果。
在负载均衡中的
proxy_pass
配置中也有相对路径代理和绝对路径代理这两种路径形式,路径加在服务器集群名后即可,机制和上述完全一模一样,大家可以自行修改尝试。
可见配置负载均衡非常简单,只需先用upstream
定义集群列表,列表名我们自定义,然后把proxy_pass
后面改成http://集群列表名
即可实现负载均衡。
在Nginx中,一共有三种负载均衡算法:
round-robin
线性轮询,也就是默认的Nginx负载均衡算法,将第一个请求转发给第一个服务器,第二个转发给第二个服务器...如此循环,就是上图的效果least-connected
最小连接,每次转发给当前接受请求数最小的服务器ip-hash
根据用户的IP地址,利用散列算出一个结果来确定把这个请求转发给哪个服务器
在默认的线性轮询算法中,我们还可以给每个服务器设定权值,例如把上述upstream
块中内容改为如下:
# 目的服务器集群列表,命名为myspringboot
upstream myspringboot {
# 用server指令声明每个服务器的地址
server 127.0.0.1:8800 weight=3; # 把这个服务器权值设为3
server 127.0.0.1:8801;
server 127.0.0.1:8802;
server 127.0.0.1:8803;
}
nginxcopy
在集群列表中,把第一个服务器的权值改成了3,这样假设来了6个请求,就会有3个请求转发给第一个服务器,剩下3个请求平摊给第2, 3, 4台服务器。
那么如何更改这个列表的负载均衡算法呢?在upstream
块第一行加入算法名即可。例如更改上述算法为ip_hash
算法:
upstream myspringboot {
# 设定为ip_hash算法
ip_hash;
# 用server指令声明每个服务器的地址
server 127.0.0.1:8800;
server 127.0.0.1:8801;
server 127.0.0.1:8802;
server 127.0.0.1:8803;
}
nginxcopy
在平时部署时,若后端涉及到用户登录的,就需要使用ip_hash
算法,因为ip_hash
算法会使得每一个用户能够固定地访问到一台被代理的Spring Boot服务器,无论这个用户发送多少个请求。而用户登录的session也只会存在一个服务器上,若用户登录后,下一个请求被转发到另一个服务器,就会导致下一个请求被判断为未登录。
当然,使用Redis分布式session可以解决这个问题。