Redis将Session 集中管理的说明
发布日期:2016-4-24 13:4:27
在分布式系统中.前提是分布式或者集群环境,常常会需要多个系统中,保持Session . nginx可以配置IP的hash,实现每次都访问同一台应用容器,从而不需要共享Session ,也有tomcat的复制. 虽然tomcat等容器可以实现Session 的复制,但是在tomcat的数量过多时,复制的延迟和性能的损失 将因为tomcat的数量直线上升. 这里可以用redis简单的将Session 集中管理.线上环境将redis高可用即可. Java对Redis的操作可以用 Jedis.spring-data-redis封装Jedis,更加易用 本文采用 spring data redis作为Redis的连接工具. 采用Sping管理. Maven pom.xml引入 org.springframework.data spring-data-redis 1.5.2.RELEASE redis.clients jedis 2.6.2 spring-redis.xml 配置 Redis的连接池和连接 class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:use-pool="true" p:pool-config-ref="poolConfig" /> p:connection-factory-ref="jedisConnFactory" /> redis.properties 连接的配置肯定是需要的 redis.host=x.x.x.x redis.port=6379 redis.pass= redis.maxWait=30000 redis.pool.maxTotal=1024 redis.pool.maxIdle=200 redis.pool.timeBetweenEvictionRunsMillis=30000 redis.pool.testOnBorrow=true 在需要使用的类中注入 @Resource protected RedisTemplate redisTemplate; 组装一下key,统一设置前缀,可以方便的管理key private String getJointName(String sid) { String key = RedisExpire.ONLINEUSER + ":" + sid;//":"为文件夹形式 return key; } 准备常量 public class RedisExpire { /** * Session 超时时间为30分钟 */ public final static Long ThirtyMinuteSecend= 30*60L;//秒 public final static String ONLINEUSER= "OnLineUser"; } 然后就可以开始操作,如在登陆时写入redis并设置Session时长. /** * 添加在线用户 * * @param sid 生成对用户的唯一id.即Session中的sessionid * source 为来源为后续app预留 * @param user * @return * @throws Exception */ public boolean addOnLinuUser(final String sid, final onLineUserInfo user, final String source) throws Exception { if (user != null && sid.trim().length() > 0) { final String key; key = getJointName(sid); Boolean falg = redisTemplate.execute(new RedisCallback() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { /*这里是存入时,序列换操作,可选 * @SuppressWarnings("unchecked") * RedisSerializer valueSerializer = * (RedisSerializer) redisTemplate * .getValueSerializer(); */ connection.select(2);//切换redis的DB可以不需要,redis默认配置为0-15共16个库,可以通过这行代码实现切换 connection.setEx(key.getBytes(), RedisExpire.ThirtyMinuteSecend, stringToByte(JSONObject.toJSONString(user)));//序列化采用了fastjson return true; } }); return falg; } return false; } 同理删除和获取,如下所示: /** * 移除在线登陆用户 * * @param sid * source 为来源为后续app预留 * @return * @throws Exception */ public boolean removeOnLinuUser(final String sid, final String source) throws Exception { if (sid != null) { final String key; key = getJointName(sid); Boolean falg = redisTemplate.execute(new RedisCallback() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { connection.select(2); Long del = connection.del(key.getBytes()); if (del == 1) { return true; } else { return false; } } }); return falg; } return false; } /** * 获取在线用户信息 * * @param sid * source 为来源为后续app预留 * @return * @throws Exception */ public onLineUserInfo getOnLinuUser(String sid, final String source) throws Exception { final String key; key = getJointName(sid); onLineUserInfo userInfo = redisTemplate .execute(new RedisCallback() { public onLineUserInfo doInRedis(RedisConnection connection) throws DataAccessException { connection.select(2); byte[] bs = connection.get(key.getBytes()); String byteToString = byteToString(bs); onLineUserInfo userinfo = JSONObject.parseObject( byteToString, onLineUserInfo.class); /*if (userinfo != null) { // 如果用户已登录,则增加在线时间 connection.expire(key.getBytes(), RedisExpire.ThirtyMinuteSecend); }*/ return userinfo; } }); return userInfo; } } 文中的 onLineUserInfo 即你需要放入Session的登陆对象,可以自行编辑 public class onLineUserInfo implements Serializable{ private String name;// 用户名字 .......... } 不管存入cookie还是重写url...系统请求是需要带上sid即可. 有人问我为什么要用顶级的key,不用Hash,因为redis的key是有上限的.主要是只有顶级的key才能有过期时间一说.这里牵涉到Redis的一些内部特征,大家可以去查阅关于Redis的文章.
|