Nginx反向代理和负载均衡

172 阅读7分钟

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会得到端口号信息:

image-20220707112225986

访问http://你的服务器地址:8800/api/name会得到节点名:

image-20220707112256002

这样就配置成功了

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一下配置

访问http://你的服务器地址/api/port

image-20220707113023874

这次是访问nginx,nginx反代到springboot项目中

通过筛选所有/api的后缀的请求去转发到javaApi中

2.绝对路径和相对路径代理

location /api {
    # 转发到目的服务器的/路径下
    proxy_pass http://127.0.0.1:8800/;
}

还是访问上述路径,结果:

image-20220801224435302

可见我们只是在上述代理的地址后面加了个/,就变成了404,怎么差别这么大呢?

这是因为这次的反向代理地址我们不仅指定了地址还指定了路径/* * 当proxy_pass后面的地址指定了路径之后,就变成了绝对路径代理。

我们上述location后面为/apiproxy_passhttp://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平坦请求,实现负载均衡

image-20220707114218078

我们可以开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可以解决这个问题。