您的位置:首页 > 数据库 > Redis

Redis将Session 集中管理

2016-02-23 08:45 615 查看
摘要: 在分布式系统中.前提是分布式或者集群环境,常常需要多个系统中,保持Session .
nginx可以配置IP的hash,实现每次都访问同一台应用容器,从而不需要共享Session ,对Java来说,也有tomcat的复制.
虽然tomcat等容器可以实现Session 的复制,但是在tomcat的数量过多时,复制的延迟和性能的损失
将因为tomcat的数量直线上升.
这里可以用redis简单的将Session 集中管理.线上环境将redis高可用即可.

在分布式系统中.前提是分布式或者集群环境,常常需要多个系统中,保持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引入

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.6.2</version>
</dependency>

spring-redis.xml 配置 Redis的连接池和连接

<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<property name="maxTotal" value="${redis.pool.maxTotal}" />
<property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}" />
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>

<bean id="jedisConnFactory"
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" />

<!-- <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean> -->
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
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<Serializable, Serializable> redisTemplate;

组装一下key,统一设置前缀,可以方便的管理key

private String getJointName(String sid) {
String ke
7fe0
y = 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<Boolean>() {
public Boolean doInRedis(RedisConnection connection)
throws DataAccessException {
/*这里是存入时,序列化操作,可选
* @SuppressWarnings("unchecked")
* RedisSerializer<onLineUserInfo> valueSerializer =
* (RedisSerializer<onLineUserInfo>) 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<Boolean>() {
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<onLineUserInfo>() {
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即可.

PS:有人问我为什么要用顶级的key,不用Hash,因为redis的key是有上限的.主要是只有顶级的key才能有过期时间一说.这里牵涉到Redis的一些内部特征,大家可以去查阅关于Redis的文章.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息