分布式session实现
分布式session大家都比较熟悉了,一般的实现方式有几种。
- 容器级别分布式session的实现
最常见容器级别的比如tomcat-redis,tomcat-memcache系列。这种实现方式的好处就是屏蔽了分布式session的细节,做到了对开发人员无感知。
- https://www.oschina.net/p/tomcat-redis-session-manager
- https://www.oschina.net/p/memcached-session-manager
但是随着springboot和docker技术的发展嵌入式容器变成大势所趋,这种方式就不太适合。
- 利用统一存储
一般的架构方案都会考虑把session独立存储在redis或者memcache种。每次使用到session的时候就从redis里面get一次。
优化一点的方案会增加个threadlocal变量,贯穿整个请求,保证一次完整的请求内不在重复从redis里面获取数据session数据。这种方案在请求结束时候的一定记得清空threadlocal变量,不然会引起下次请求的session混乱。
这种方案的缺点是请求量大的时候,由于大量的数据通过缓存获取,导致缓存服务的数据吞吐量太大,带宽容易跑满。当redis出现异常的时候应用会马上无法响应。
二级分布式session实现
利用二级缓存实现分布式session就能完美解决以上问题。
如图所示,应用程序在获取session数据的时候会先从内存中查询,如果没有才会从redis里面获取。
J2Cache是oschina网站实战的产物,它不是一个缓存框架,是一个缓存框架的桥梁。它利用现有优秀的内存缓存框架作为一级缓存,而把 Redis 作为二级缓存。
虽然他支持的一级缓存实现不少,我在这里选择Caffeine作为一级缓存,redis为二级缓存进行演示。
引入J2Cache
<dependency>
<groupId>net.oschina.j2cache</groupId>
<artifactId>j2cache-core</artifactId>
<version>2.7.8-release</version>
</dependency>
配置一级缓存
caffeine.properties
增加一行配置session=1000, 30m 配置缓存实效时间为30分钟也就是session的实效时间
配置二级缓存
j2cache.properties 配置一级缓存二级缓存的提供方式
j2cache.broadcast = redis j2cache.L1.provider_class = caffeine j2cache.L2.provider_class = redis
j2cache.properties中配置redis连接地址
redis.hosts = 127.0.0.1 redis.timeout = 2000 redis.password = redis.database = 0 redis的index
J2CacheKit 简单封装下
public class J2CacheKit { private static CacheChannel cache; static void init(CacheChannel cache) { J2CacheKit.cache = cache; } public static CacheChannel getCacheChannel(){ return cache; } @SuppressWarnings("unchecked") public static <T> T get(String cacheName, Object key) { try { CacheObject cacheObject = cache.get(cacheName, key.toString()); return cacheObject != null ? (T) cacheObject.getValue() : null; } catch (Exception e) { LogKit.error(e.toString(), e); } return null; } public static void put(String cacheName, Object key, Object value) { try { cache.set(cacheName, key.toString(), (Serializable) value); } catch (Exception e) { LogKit.error(e.toString(), e); } } public static void remove(String cacheName, String... keys) { try { cache.evict(cacheName, keys); } catch (Exception e) { LogKit.error(e.toString(), e); } } public static void removeAll(String cacheName) { try { cache.clear(cacheName); } catch (Exception e) { LogKit.error(e.toString(), e); } } @SuppressWarnings("unchecked") public static <T> T get(String cacheName, Object key, IDataLoader dataLoader) { Object value = get(cacheName, key); if (value == null) { value = dataLoader.load(); if (value != null) { put(cacheName, key, value); } } return (T) value; } public static Collection<String> getKeys(String cacheName) { try { Collection<String> keys = cache.keys(cacheName); return keys == null ? new ArrayList<String>(keys) : null; } catch (Exception e) { LogKit.error(e.toString(), e); } return null; } }
当然作者也提供了更佳的完整的模块实现
代码地址如下,有兴趣可以参考下
https://gitee.com/ld/J2Cache/tree/master/modules/session-manager
本文暂时没有评论,来添加一个吧(●'◡'●)