使用Nginx、Redis集群实现Tomcat集群负载均衡,session共享

多Tomcat运行、集群搭建及Session共享方案
本文介绍了配置多个Tomcat同时运行的方法,包括修改环境变量、catalina.sh和server.xml。还讲述了使用Nginx搭建Tomcat集群实现负载均衡,但会有session不同步问题。接着给出解决办法,如ip_hash、Tomcat - Redis - Session_manager、spring session等,最后介绍了在springboot中的实现及测试。

1、配置多个Tomcat同时运行

1.1、修改环境变量 将tomcat 复制两份出来

#将之前解压的tomcat文件夹直接复制并重命名为‘apache-tomcat_2’、‘apache-tomcat_3’
cp -r apache-tomcat apache-tomcat_2
cp -r apache-tomcat apache-tomcat_3
复制代码

修改环境变量,介入如下内容

vi /etc/profile
复制代码
######### tomcat 1 ###########
CATALINA_BASE=/usr/local/tomcat/apache-tomcat
CATALINA_HOME=/usr/local/tomcat/apache-tomcat
TOMCAT_HOME=/usr/local/tomcat/apache-tomcat
export CATALINA_BASE CATALINA_HOME TOMCAT_HOME

########## tomcat 2 ##########
CATALINA_BASE_2=/usr/local/tomcat/apache-tomcat_2
CATALINA_HOME_2=/usr/local/tomcat/apache-tomcat_2
TOMCAT_HOME_2=/usr/local/tomcat/apache-tomcat_2
export CATALINA_BASE_2 CATALINA_HOME_2 TOMCAT_HOME_2

########## tomcat 3 ###########
CATALINA_BASE_3=/usr/local/tomcat/apache-tomcat_3
CATALINA_HOME_3=/usr/local/tomcat/apache-tomcat_3
TOMCAT_HOME_3=/usr/local/tomcat/apache-tomcat_3
export CATALINA_BASE_3 CATALINA_HOME_3 TOMCAT_HOME_3

复制代码

保存退出,使配置文件立即生效。

source /etc/profile
复制代码

1.2、修改 对应tomcat中的 catalina.sh,添加环境变量

第二个tomcat为例

vi catalina.sh
复制代码
# 修改 和 /etc/profile 中的 变量相同
export CATALINA_BASE=$CATALINA_BASE_2
export CATALINA_HOME=$CATALINA_HOME_2
复制代码

1.3、修改conf下配置文件 server.xml

上面三处的端口修改一下即可,这样多台tomcat就可以同时运行了。

2、使用Nginx搭建tomcat集群

这个主要就是在配置文件,简单的配置就能达到负载均衡的效果

    #upstream设置,设置代理服务器(负载均衡池),默认的负载均衡方式是轮询,另外一种是ip_hash
    upstream mynginx{
        #想要负载的服务器地址列表
        server 192.0.0.179:8088;
        server 192.0.0.179:8089;
        server 192.0.0.179:8090;
    }

    server {
        listen  8888;
        server_name  192.0.0.179;


        location / {
            root   html;
            index  index.html index.htm;
            add_header backendIP $upstream_addr;
            proxy_pass  http://mynginx;#注意要与定义的upstream模块名称相同
        }

    }

复制代码

这样直接访问地址:192.0.0.179:8888 , 就可以根据轮询 的情况给我们分发到定义的服务器列表中的一个。

但是这时就会出现一个问题,这样同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态

3、解决办法

在网上也看到了不少的解决办法,这里也简单的说一下

3.1、ip_hash:ip_hash技术能够将某个ip的请求定向到同一台后端,这样一来这个ip下的某个客户端和某个后端就能建立起稳固的session

ip_hash是在upstream配置中定义的

    upstream mynginx{
        #想要负载的服务器地址列表
        server 192.0.0.179:8088;
        server 192.0.0.179:8089;
        server 192.0.0.179:8090;
        ip_hash;
    }
复制代码

ip_hash是容易理解的,但是因为仅仅能用ip这个因子来分配后端,因此ip_hash是有缺陷的,并不能很好的体现集群的优势

3.2、Tomcat-Redis-Session_manager

使用Tomcat-redis-session-manager来实现Tomcat集群部署中的Session共享,这种方式可以实现,但是需要自己去编译源码,还需要修改tomcat 的配置文件,比较繁琐,所以不是很推荐。

3.3、spring session

spring-session在无需绑定web容器的情况下提供对集群session的支持。并提供对以下情况的透明集成:

  • HttpSession:容许替换web容器的HttpSession
  • WebSocket:使用WebSocket通信时,提供Session的活跃
  • WebSession:容许以应用中立的方式替换webflux的webSession

3.4、在springboot中如何实现:

一、springboot 集成

1、添加Maven依赖:

        <!--spring boot 与redis应用基本环境配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--spring session 与redis应用基本环境配置,需要开启redis后才可以使用,不然启动Spring boot会报错 -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
复制代码

2、添加@EnableRedisHttpSession来开启spring session支持,配置如下:

@Configuration
//开启spring session支持
@EnableRedisHttpSession
public class RedisSessionConfig {
}

复制代码

3、因为之前弄了redis集群,这里也可以配合使用,无奈之前挖了好多坑,也是好不容易才填上。。。。。。

如果是单纯的使用springsession,这里已经基本完成了,但是.......之前搞了shiro,session的管理已经交给了 shiro管理,这里还得重新倒腾一下,还要让shiro使用redis集群进行工作

将之前的shiro+redis缓存插件更换成‘3.1.0’ 版本,shiro-redis 3.1.0 开始支持redis集群配置

        <dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis</artifactId>
            <version>3.1.0</version>
        </dependency>
复制代码

在贴一下相关的配置文件:

redis:
    database: 0 # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
#    host: 127.0.0.1
#    port: 6379
    # redis.cluster
    password:
    cluster:
      nodes: 192.0.0.179:7001,192.0.0.179:7002,192.0.0.179:7003,192.0.0.179:7004,192.0.0.179:7005,192.0.0.179:7006

    lettuce:
      pool:
          #最大连接数
        max-active: 1000
          #最大阻塞等待时间(负数表示没限制)
        max-wait: -1
          #最大空闲
        max-idle: 1000
          #最小空闲
        min-idle: 100
      #连接超时时间
    timeout: 1000

  # 这里需要注意如果没有集成shiro,应该是要指定一下的,具体没试过。。
  #session:
  #  store-type: redis
复制代码

修改之前的ShiroConfig,将RedisManager更换为RedisClusterManager,一些使用到RedisManager方法的地方直接替换成RedisClusterManager

    #注入配置文件pojo
    @Autowired
    private RedisConf2 properties2;
    
    ---------------------------------
    
    @Bean
    public RedisClusterManager redisClusterManager(){
        RedisClusterManager redisClusterManager = new RedisClusterManager();
        redisClusterManager.setHost(properties2.getNodes());
        return redisClusterManager;
    }

复制代码

这里的host可以直接获取配置文件redis节点的配置,从而更加方便灵活

#配置文件读取
@Configuration
public class RedisConf2 {

    @Value("${spring.redis.cluster.nodes}")
    private String nodes;

    public String getNodes() {
        return nodes;
    }

    public void setNodes(String nodes) {
        this.nodes = nodes;
    }
}

复制代码

配置文件的读取方式有几种,可以根据自己的实际情况来定,我这里是单独抽象了一个pojo,在读取配置参数的地方通过‘ @Autowired’ 注入即可

这里还有一个需要注意的地方,这样直接启动会报错,配置文件读取不到,在网上找了很久解决方案,找到了比较简单的一个,修改shiro的getLifecycleBeanPostProcessor 方法,加上static,让其变成静态方法

    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
复制代码

这样基本算是完事了,将项目打包进行测试

4、测试,为了方便就不放到nginx里启动了,直接打包在本地用不同端口启动

清空redis:

192.0.0.179:7002> flushall
OK
192.0.0.179:7002> keys *
(empty list or set)
192.0.0.179:7002> 

复制代码

第一个负责存入session

第二个负责读取session

再看一下redis,session信息已经存进去了

知识点:sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。 session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid; 存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值