详解springboot中redis的使用和分布式session共享问题
对于分布式使用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
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!!!
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:
sessionid
看redis中,可以看到失效时间,sessionid等
sessionid
共享session
另外找一个机器,照着这个配置再来一遍,自动启用session共享,因为sessionid都存在了同一个redis中。奏是这么简单。挽起袖子开始干吧。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。