文档章节

Redis将Session 集中管理

ParkJun
 ParkJun
发布于 2016/02/22 12:51
字数 1016
阅读 11970
收藏 276

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

© 著作权归作者所有

下一篇: 我是一个线程
ParkJun
粉丝 15
博文 9
码字总数 5757
作品 0
成都
高级程序员
私信 提问
加载中

评论(31)

ParkJun
ParkJun 博主

引用来自“Dancer-mno”的评论

能看下整个项目吗
整个项目?
Dancer-mno
Dancer-mno
能看下整个项目吗
MGL_TECH
MGL_TECH
最好不要动代码
MGL_TECH
MGL_TECH

引用来自“余俊材”的评论

引用来自“丑矬穷”的评论

php只有一行
没办法..世界上最好的语言,没有之一,我Java 无法企及

只有更好没有最好、说某某语言是最好的基本都是二流货色或者脑子残废!
引鸩怼孑
引鸩怼孑

引用来自“余俊材”的评论

引用来自“南湖船老大”的评论

恰恰相反,我还写了个扩展类完全禁用了tomcat的session,全部使用cookies,天然的分布式
6666

777720
ParkJun
ParkJun 博主

引用来自“南湖船老大”的评论

恰恰相反,我还写了个扩展类完全禁用了tomcat的session,全部使用cookies,天然的分布式
6666
南湖船老大
南湖船老大
恰恰相反,我还写了个扩展类完全禁用了tomcat的session,全部使用cookies,天然的分布式
ParkJun
ParkJun 博主

引用来自“星光似霰”的评论

我也准备如此实现,不知使用中可否遇到过什么问题没13
比如安全性,这些因项目不同,自行考虑了.方法还是比较多
ParkJun
ParkJun 博主

引用来自“星光似霰”的评论

我也准备如此实现,不知使用中可否遇到过什么问题没13
我们项目使用CXF 向外暴露接口,就这样来管理session,当然细节上不一样,这里只是这样的思路.view与数据分离,作为数据来源,已经上线. 5wow.cn
星光似霰
星光似霰
我也准备如此实现,不知使用中可否遇到过什么问题没13
分布式Session集中存储方案

在文章分布式web架构中Session管理的方法中讲了分布式Session管理的4种办法,其中第4种的Session集中存储实际运用比较广泛,下面来讲解这种的实现方案。 目前常用的Session集中管理方案有两种...

刘诗书
2017/11/23
0
0
Session集中管理方案中,怎么与之前写的SessionListener兼容,使之能触发?

现在在项目中需要使用Session集中管理方案,把用户的Session数据存放到Redis服务器中,参照memcached-cache-filter和Spring-Session,使用一个filter将用户请求拦截,然后使用自己写的Sessi...

焕世Nero
2016/04/08
374
3
Spring-Session基于Redis管理Session

系列文章 Nginx+Tomcat关于Session的管理 Tomcat Session管理分析 Spring-Session基于Redis管理Session 前言 在上文Tomcat Session管理分析介绍了使用tomcat-redis-session-manager来集中式管...

ksfzhaohui
2018/06/29
2.5K
4
补习系列(15)-springboot 分布式会话原理

[TOC] 一、背景 在 补习系列(3)-springboot 几种scope 一文中,笔者介绍过 Session的部分,如下: 对于服务器而言,Session 通常是存储在本地的,比如Tomcat 默认将Session 存储在内存(Conc...

美码师
2018/12/16
0
0
nginx笔记4-负载均衡带来的问题以及解决办法

接着笔记3,将笔记三的改造一下,现在分别启动两个Tomcat,在页面获取session。如图所示: tomcat2的session: tomcat1的session: 根据上图发现,每个tomcat取到的session不一样。因此nginx负...

狂小白
2018/01/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周一乱弹 —— 年迈渔夫遭黑帮袭抢

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @tom_tdhzz :#今日歌曲推荐# 分享Elvis Presley的单曲《White Christmas》: 《White Christmas》- Elvis Presley 手机党少年们想听歌,请使劲...

小小编辑
36分钟前
86
6
CentOS7.6中安装使用fcitx框架

内容目录 一、为什么要使用fcitx?二、安装fcitx框架三、安装搜狗输入法 一、为什么要使用fcitx? Gnome3桌面自带的输入法框架为ibus,而在使用ibus时会时不时出现卡顿无法输入的现象。 搜狗和...

技术训练营
昨天
5
0
《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
昨天
8
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
昨天
10
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部