欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解springboot中redis的使用和分布式session共享问题

程序员文章站 2024-02-15 10:00:58
对于分布式使用nginx+tomcat实现负载均衡,最常用的均衡算法有ip_hash、轮训、根据权重、随机等。不管对于哪一种负载均衡算法,由于nginx对不同的请求分发到某...

对于分布式使用nginx+tomcat实现负载均衡,最常用的均衡算法有ip_hash、轮训、根据权重、随机等。不管对于哪一种负载均衡算法,由于nginx对不同的请求分发到某一个tomcat,tomcat在运行的时候分别是不同的容器里,因此会出现session不同步或者丢失的问题。

实际上实现session共享的方案很多,其中一种常用的就是使用tomcat、jetty等服务器提供的session共享功能,将session的内容统一存储在一个数据库(如mysql)或缓存(如redis)中。

本文旨在解决分布式系统的session如何共享问题,大致思路:session放入redis。其他解决方案:持久化、放cache等都可以,但是自从有了redis,这完全可以变的简简单单。

本文大致分两步:

1.springboot中如何使用redis。
2.redis如何解决session共享

pom依赖

  <!--redis配置开始-->
  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-redis</artifactid>
  </dependency>
  <dependency>
   <groupid>org.springframework.data</groupid>
   <artifactid>spring-data-redis</artifactid>
   <version>${spring-data-redis.version}</version>
  </dependency>
  <dependency>
   <groupid>redis.clients</groupid>
   <artifactid>jedis</artifactid>
   <version>${jedis.version}</version>
  </dependency>
  <dependency>
   <groupid>org.springframework.session</groupid>
   <artifactid>spring-session-data-redis</artifactid>
  </dependency>
  <!--redis配置结束-->

添加redis配置类

该配置类同样可以配置缓存失效时间等。

package com.mos.quote.config;

import com.fasterxml.jackson.annotation.jsonautodetect;
import com.fasterxml.jackson.annotation.propertyaccessor;
import com.fasterxml.jackson.databind.objectmapper;
import org.springframework.cache.cachemanager;
import org.springframework.cache.annotation.cachingconfigurersupport;
import org.springframework.cache.annotation.enablecaching;
import org.springframework.cache.interceptor.keygenerator;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.data.redis.cache.rediscachemanager;
import org.springframework.data.redis.connection.redisconnectionfactory;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.data.redis.core.stringredistemplate;
import org.springframework.data.redis.serializer.jackson2jsonredisserializer;

/**
 * @author administrator
 */
@configuration
@enablecaching
public class redisconfig extends cachingconfigurersupport {
  @bean
  public keygenerator keygenerator(){
    return (target, method, params) -> {
      stringbuilder sb = new stringbuilder();
      sb.append(target.getclass().getname());
      sb.append(method.getname());
      for (object obj : params) {
        sb.append(obj.tostring());
      }
      return sb.tostring();
    };
  }

  @bean
  public redistemplate<string, string> redistemplate(redisconnectionfactory factory) {
    stringredistemplate template = new stringredistemplate(factory);
    jackson2jsonredisserializer jackson2jsonredisserializer = new jackson2jsonredisserializer(object.class);
    objectmapper om = new objectmapper();
    om.setvisibility(propertyaccessor.all, jsonautodetect.visibility.any);
    om.enabledefaulttyping(objectmapper.defaulttyping.non_final);
    jackson2jsonredisserializer.setobjectmapper(om);
    template.setvalueserializer(jackson2jsonredisserializer);
    template.afterpropertiesset();
    return template;
  }

  @bean
  public cachemanager cachemanager(redistemplate<string,string> redistemplate) {
    rediscachemanager rcm = new rediscachemanager(redistemplate);
    //设置缓存过期时间
    rcm.setdefaultexpiration(600000);
    return rcm;
  }
}

配置redis服务

# redis数据库索引(默认为0)
spring.redis.database=0
# redis服务器地址
spring.redis.host=192.168.1.118
# redis服务器连接端口
spring.redis.port=6381
# redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

单元测试

1、set值(字符串)

  @test
  public void put(){
    stringredistemplate.opsforvalue().set("test001","test001");
    assert.assertequals("test001", stringredistemplate.opsforvalue().get("test001"));
  }

往redis放一个key为test001、value为test001的值,然后查看redis

详解springboot中redis的使用和分布式session共享问题

key=test001

2、set值(object)

 @test
  public void testobj() throws exception {
    sysuser user=new sysuser();
    user.setid("123456");
    user.setname("张三");
    valueoperations<string, sysuser> operations=redistemplate.opsforvalue();
    operations.set("user1", user);
    operations.set("user2", user,5, timeunit.seconds);
    thread.sleep(6000);
    assert.assertfalse(redistemplate.haskey("user2"));
  }

往redis分别放key为user1和user2的对象,user2设置5秒失效,线程等待6秒再完成,期望结果:redis中有user1,没有user2,bingo!!!

详解springboot中redis的使用和分布式session共享问题

objtest

解决session共享

使用spring-session-data-redis实现session共享,pom中引入该依赖(上文已添加),添加sessionconfig配置类。
对,没看错,只需要这个就够了。最长有效时间根据自己情况随意配置即可。

package com.mos.quote.config;

import org.springframework.context.annotation.configuration;
import org.springframework.session.data.redis.config.annotation.web.http.enableredishttpsession;

/**
 * @author administrator
 */
@configuration
@enableredishttpsession(maxinactiveintervalinseconds = 3000)
public class sessionconfig {
}

测试

写一个简单controller,如下

@requestmapping("testsessiontimeout")
  public string testsessiontimeout(string id,httpsession session,model model){
    area area = areaservice.getbyid(id);
    system.out.println("sessionid-------->"+session.getid());
    model.addattribute("area",json.tojsonstring(area));
    session.setattribute("area",json.tojsonstring(area));
    return "demo/test1";
  }

这里可以看到sessionid:

详解springboot中redis的使用和分布式session共享问题

sessionid

看redis中,可以看到失效时间,sessionid等

详解springboot中redis的使用和分布式session共享问题

sessionid

共享session

另外找一个机器,照着这个配置再来一遍,自动启用session共享,因为sessionid都存在了同一个redis中。奏是这么简单。挽起袖子开始干吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。