【快速上手系列】Nginx快速搭建与分别模拟Tomcat和SpringBoot集群进行反向代理测试

【快速上手系列】Nginx快速搭建与分别模拟Tomcat和SpringBoot集群进行反向代理测试

简介

Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器。

具体百度吧,大差不差的。

相关概念

代理

在Java设计模式中,代理模式是这样定义的:给某个对象提供一个代理对象,并由代理对象控制原对象的引用。

正向代理

访问外网(指在客户端进行一些设置,比如使用路由器进行正向代理来访问互联网或使用VPN来访问)

反向代理

反向代理和正向代理的区别就是:正向代理代理客户端,反向代理代理服务器。
反向代理,其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器IP地址

百度百科的说法:反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。简单来说就是真实的服务器不能直接被外部网络访问,所以需要一台代理服务器,而代理服务器能被外部网络访问的同时又跟真实服务器在同一个网络环境,当然也可能是同一台服务器,端口不同而已。

负载均衡

负载均衡也是Nginx常用的一个功能,负载均衡其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。简单而言就是当有2台或以上服务器时,根据规则随机的将请求分发到指定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡。而Nginx目前支持自带3种负载均衡策略,还有2种常用的第三方策略。

使用

打开

解压nginx,双击nginx.exe,成功运行后可以访问localhost路径,成功后可以看到Nginx的欢迎页面

请添加图片描述

退出的话最好使用任务管理器,因为可能关不掉,不过我们也可以使用bat文件来进行退出,但是可能有缓存或者失效,使用的时候可以注意一些

退出

我们可以新建一个txt,然后编辑

:: 先切换到nginx的磁盘目录
D:
:: 再切换到ngixn的根目录
cd D:\Program Files\nginx-1.12.2\nginx-1.12.2
:: 关闭nginx
nginx -s quit

然后把其改成bat文件即可运行,可以看看效果(假性失效可能是因为浏览器缓存,可以换一个浏览器试试)

然后我们就可以进行测试部分的操作了

测试

测试Tomcat项目(比如Maven项目)

因为这是一个测试,所以我用自己的一台电脑来模拟集群操作来达到测试使用Nginx的目的。

模拟Tomcat部分

首先我们来模拟两台服务器,也就是说我们有两个相同的项目在两个不同的Tomcat上运行

1、新建一个文件夹(tomcat-nginx-test)

请添加图片描述

2、在其下面新建两个文件夹(t1、t2)

请添加图片描述

3、在t1、t2两个文件夹中分别放置两个Tomcat

请添加图片描述

请添加图片描述

4、分别更改t1、t2中Tomcat下conf中的server.xml文件

在这里需要分别更改三个地方的端口号(当然,如果你知道怎么做,那么只改其中一个就可以,只是需要两个Tomcat端口号不冲突即可)

需要更改的第一部分端口号:

请添加图片描述

第二部分:

请添加图片描述

第三部分:

请添加图片描述

5、分别进到t1、t2中Tomcat下webapps中新建一个文件夹(nginx-test)再新建一个index.html

这两个项目文件夹名应该一致(包括文件)最好是这样比较好

6、分别在两个index.html中写一个内容

我这里写的测试内容为t1、t2,就像这样:

请添加图片描述

7、分别进到t1、t2中Tomcat下的bin目录中点击startup.bat来分别运行两个Tomcat服务器

请添加图片描述

可以看到图中我的两个Tomcat服务器都成功启动了(如果没有启动成功应检查端口是否冲突问题)

请添加图片描述

,且能够正常访问

如果没问题,那么下一步

Nginx部分

1、打开Nginx路径下的conf文件夹下的nginx.conf文件进行配置

如图,一些是默认的不需要改

请添加图片描述

其它
负载均衡设置

如果要进行负载均衡的操作:

upstream servertest {
    
      
    server 192.168.1.111:8080 down;   
    server 192.168.1.111:8081 weight=3;  
    server 192.168.1.111:8082;  
    server 192.168.1.111:8083 backup; 
}  
server {
    
    
        listen       80; #监听端口
        server_name  localhost;  #监听地址 
        location / {
    
    
            proxy_pass   http://servertest; #请求转向servertest 定义的服务器列表
            root   html;
            index  index.html index.htm;
        }
}

说明:
down:表示单前的server暂时不参与负载
Weight:默认为1.weight越大,负载的权重就越大。
max_fails:允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误(服务器出问题进行限制的的策略)
fail_timeout:  max_fails 次失败后,暂停的时间。(限制后重连时间策略)
Backup:其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻(备用机)
使用假性域名进行测试( 域名映射
  1. 找到电脑C:\Windows\System32\drivers\etc下host文件并打开
  2. 127.0.0.1 www.Tuerlechat.com 将www.Tuerlechat.com映射到127.0.0.1上
  3. 在nginx中配置server中server_name www.Tuerlechat.com
2、运行 localhost/nginx-test/index.html 路径即可

请添加图片描述

请添加图片描述

不断刷新此页面,可以发现我们访问的路径并没有变化,但是显示的内容却是不一样的,这说明Nginx成功的进行了反向代理,让用户从客户端实现无感知的变化,但在系统实际操作时,我们会发生session共享的问题

其它:session共享解决方案
1.使用客户端的cookie作为存放登录信息的媒介

cookie是将用户登录信息存储在用户终端的数据载体,与session的最大区别就是,session是存储在服务器端的;所以这就很容易解决这种session的多台服务器共享问题。当我们客户端进行登录的时候,访问的是服务器a,登录成功之后我们将session抽取出来存放在客户端的cookie里面;然后当我们客户端第二次进行访问的时候,访问的是服务器b,这次我们先在服务器b去查找是否有登录成功的session,如果为空,我们再对客户端的cookie进行查找,如果cookie里面已经存储有session,那么再将cookie里面的session同步到服务器b,那么整个流程就能走通了,用户也不用再次登录;

优点:这种方法实现起来简单,方便,很容易上手操作,不会加大数据库的负担;

缺点:如果客户端把cookie禁掉了的话,那么session就无法同步了,而且cookie的安全性不高,很容易外部被伪造使用;

2.使用mysql数据库存储session

既然每个服务器都需要使用同一个session,那么我们可以将session存放在同一个数据库里面,每次访问的时候,我们去数据库check一下是否有这个session或者这个session是否过期,然后就可以进行多台服务器的session同步了;

优点:使用这种方法简单、方便,很容易上手操作;

缺点:使用数据库来同步session,会加大数据库的IO,增加数据库的负担;同时,每次访问都需要拦截请求、查询数据库,导致多一层访问的业务层以及浪费读取数据库session时间;

3.使用memcache或者redis等缓存机制存放session

使用memcache或者redis等分布式缓存机制存放session数据,是现在很多大型项目负载均衡同步session的热门方案;它的原理是项目都使用的是同一个地方的memcache或者redis的缓存,当用户登录的时候,会把session存放在缓存里面,之后不管访问的是项目的那一台服务器,都会从同一个地方去获取session缓存,这样就很轻松实现了session同步;

优点:用缓存来同步session,不会加大数据库的负担,也不用手动去判断session是否存在或过期,省去部分业务逻辑,同时,由于redis等缓存是存放于服务器端,安全性也大大提高;

缺点:memcache或redis把内存分成很多种规格的存储块,有块就有大小,这种方式也就决定了,memcache或redis不能完全利用内存,会产生内存碎片,如果存储块不足,还会产生内存溢出。

4.ip_hash

nginx中的ip_hash技术能够将某个ip的请求固定到同一台后端应用服务器,这样一来这个ip下的某个客户端和某个后端就能建立起稳固的session,ip_hash是在upstream配置中定义的:

    upstream servertest {
    
      
    server 192.168.1.111:8080 down;   
    server 192.168.1.111:8081 weight=3;  
    server 192.168.1.111:8082;  
    server 192.168.1.111:8083 backup; 
    ip_hash;
}  

优点:ip_hash算法可以把一个ip映射到一台服务器上,这样可以解决session同步的问题。这样每个访客固定访问一个后端服务器,可以解决session的问题;

缺点:使用ip_hash进行session共享,它的原理是为每个访问者提供一个固定的访问ip,让用户只能在当前访问的服务器上进行操作,保持了session同步的,但是也造成了负载不均衡的问题,如果当前用户访问的服务器挂了的话,那就会出现问题了;

实际上Nginx给出的方式并没有真正的解决此问题,算是解决了但是没完全解决一样,不过一些情况下来说也算是比较方便的

5、相对最优解: springsession (springboot)

1.导入jar

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>

2.config包下编写配置类

@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
    
    
}

接下来我们来测试Nginx来对模拟SpringBoot项目集群进行反向代理的操作

测试SpringBoot项目

因为Nginx配置文件改好了,懒的动了,所以就接下来的Springboot项目也改成相应的端口进行测试

我们可以打开自己的SpringBoot项目,

如果你不会搭建SpringBoot项目,可以看这篇: (2条消息) 【快速搭建系列】idea傻瓜式快速搭建springboot框架_Tuerlechat,的博客-CSDN博客_idea springboot框架搭建

然后创建两个html文件,内容分别为:

我这里用了thymeleaf模板引擎,你可以自己传session值,或导入依赖:

<dependency>  
    <groupId>org.springframework.boot</groupId>   
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

第一个项目的

index.html、index1.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>8080</title>
</head>
<body>
<div>
    <br/><span>我是8080</span>
    <br/><span th:text="${session.name}">我是8080,这里没有session</span>
</div>
</body>
</html>

Contoller

/**
 * @Author Tuerlechat,
 * @Date 2022/11/16
 */
@Controller
@RequestMapping("/pro")
public class ProviderController {
    
    

    @Autowired
    private ProviderService providerService;

    @RequestMapping("/findProviderList")	//存个session
    public String findProviderList(HttpSession session) {
    
    
        session.setAttribute("name","我是8080的session");
        return "index";
    }
    
    @RequestMapping("/findProviderList1")	//什么都不存
    public String findProviderList() {
    
    
        return "index";	
    }
    
}

第二个项目的

index.html、index1.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>8081</title>
</head>
<body>
<div>
    <br/><span>我是8081</span>
    <br/><span th:text="${session.name}">我是8081,这里没有session</span>
</div>
</body>
</html>

Controller

/**
 * @Author Tuerlechat,
 * @Date 2022/11/16
 */
@Controller
@RequestMapping("/pro")
public class ProviderController {
    
    

    @Autowired
    private ProviderService providerService;

    @RequestMapping("/findProviderList")	//存个session
    public String findProviderList(HttpSession session) {
    
    
        session.setAttribute("name","我是8081的session");	
        return "index";
    }
    
    @RequestMapping("/findProviderList1")	//什么都不存
    public String findProviderList() {
    
    
        return "index";	
    }
    
}

测试

接下来有两种方式可以测试,

这两个SpringBoot项目可以直接在idea上面用不同的端口号来进行测试,

也可以将它们进行打包分别测试,

这里为了能够都用到,所以我使用一个项目使用idea、另一个项目进行打包运行来进行测试

测试准备

这两个项目端口号是不一样的,所以我们先对第二个进行打包(8081)

SpringBoot打包项目运行

操作如图

请添加图片描述

然后进入到此项目的target文件夹下来运行打包好的jar

请添加图片描述

按住shift键然后右击用powershell打开(cmd也可以,需要管理员权限)

输入java -jar 打包项目文件(jar)回车

请添加图片描述

可以看到springboot成功运行

然后我们在idea中开启第一个项目(8080)

成功开启后继续

测试开始

我们来打开Nginx(如果没开的话)

访问你相应页面的Controller

先进入需要存sesssion的Controller

请添加图片描述

可以看到session已存入

接着我们访问不需要存sesssion的Controller

请添加图片描述

可以发现存入的session并没有实现共享,这样就会导致很多问题

解决session共享具体操作
1、导入maven依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
    <version>1.3.8.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>
2、在config包下创建RedisSessionConfig.java
package com.r.springboot1.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

/**
 * 解决nginx的共享session问题
 * @Author Tuerlechat,
 * @Date 2023/2/10
 */
@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
    
    
}
3、配置yml中的redis设置
spring:
  redis:
    database: 1
    password: # 密码
4、打开redis,重复刚才的测试

先进入需要存sesssion的Controller

请添加图片描述

可以看到session已存入

接着我们访问不需要存sesssion的Controller

请添加图片描述

可以发现存入的session实现了共享,这样就完成啦

其它

我们刚才在运行的一些session会存入redis,我们可以看到上面存入的session和过期时间,还有一些简要信息

请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_55452293/article/details/129435630