论坛首页 Java企业应用论坛

SNA方案之session store调研

浏览 39030 次
该帖已经被评为良好帖
作者 正文
   发表时间:2008-06-05  

SNA方案中,session的存放是一个重要方面。javaeye中提出的解决方案主要基于memcached:

 

codeutil通过hack tomcat6的session manage相关类将标准的servlet session存储在memcached中。该hack解决了一部分问题,但是最终没有完全绕过ManagerBase中的sessions实例和StandardSession中的attributes实例。从代码上看,群集环境中,存在着各个JVM中的sessions实例和attributes实例无法与memcached保持同步的问题,继而隐藏着session dirty或者expire机制失效的BUG。

 

另外一种方案是自定义Map<String,Map<String,Serializable>>来取代servlet容器的SessionStore机制。使用memcached作为underlying store的,仍然需要解决session expire的问题。关于memcached管理session expire的问题,balaschen等hack了memcached的代码。每次get操作的时候更新expire值,继而试图让memcached自行管理。这种方案限于每个session只能作为一个key/value pair存放于memcached。而通常更有效的存储结构是:

sessionkey:["attr1","attr2","access_timestamp"]

sessionkey_attr1:{}

sessionkey_attr2:{}

 

ROR社区使用cookie_store,很好。虽然没有看过其实现机制,但是以java的实现该是这样:

new ObjectOutputStream(new GZIPOutputStream(new CipherInputStream(new Base64OutputStream(out),cipher))).writeObject(state);

 

我个人感觉cookie item 4k的容量,存放压缩过的信息已经足够了。关于session中应该/不应该存放什么的讨论,javaeye有很多。我个人总结是,session中存放用户与服务端资源交互产生的、无法由服务端自行决定存放的状态信息。

 

 

如果仍然需要session_store的话,我还是更倾向于自定义session结构这种方案。虽然丧失了一部分容器session 机制的好处(比如event,标准接口),但是可以免去hack的痛苦,且与容器无关,轻量级。使用dbcached(memcached+nmdb+qdbm)来作为underlying store,增加了持久、故障转移等功能。

 

但是,session iterate仍然是待解决的问题。

 

为什么需要iterate?可以更加灵活的进行expire,还有在线人数统计这类常见的需求。

 

虽然qdbm提供的java client中Villa可以按照key的前缀进行iterate,但是client无法使用nmdb独占打开的那个db,而nmdb又没有提供java client,更沮丧的是其client规范中规定的可操作方法并没有iterate。目前正在调研其他解决方案。

 

 

还有基于terracotta的JVM-level clustering来管理session。很重量级,这里不表。

 

   发表时间:2008-06-05  
用mysql memory table的话,你就可以iterate了。不过mysql memory table有一个缺陷,内存分配的浪费很严重,ebay有一个工程师写了一个patch在很大程度上解决了这个问题,还获了mysql年度的奖,他的patch在这里:

http://code.google.com/p/mysql-heap-dynamic-rows/
0 请登录后投票
   发表时间:2008-06-05  
谢谢robbin提供的这个。不然还在qdbm上捣鼓呢,一叶障目啊。

幸好,我想存放的是定长的字段
sessionid char(32)
access_at timestamp

还有一个相关的,使用Google的开源TCMalloc库,提高MySQL在高并发情况下的性能

使用mysql memory table,我需要在存放item到memcached时设置一个足够长的expire时间,避免因为mysql的故障引起的无法expire那些不存在于memory table中的session。

0 请登录后投票
   发表时间:2008-06-06  
我也有个方案,不知行不行(程序已实现,就是还没有实际用过)

memcached部分
sessionId_attr_names=属性名列表(attr1,attr2)
sessionId_attr1=attr1value
sessionId_attr2=attr2value
sessionId_last_accessed_time=最后访问时间

cookie部分
上一次访问时间(last_accessed_time)

db部分(内存表)
就一个字段sessionId(memcached不支持iterate没什么好办法)

以下如何实现

创建sessionId时,才用db增加sessionId.

增加属性时,需要修改sessionId_attr_names和增加相关sessinId_attr(name)

读取属性时,直接读sessionId_attr(name)

删除属性时,需要修改sessionId_attr_names和删除相关sessionId_attr(name)

要使expire有效,就要使用到last_accessed_time,这里不是每次请求都设置memcached的sessionId_last_accessed_time,这样会对memcached开销太大,在filter中,设置一个"容忍偏差"时间我的设置为5秒,只有在cookie的last_accessed_time + 这个容忍偏差 >当前时间时,才要设置memcached的last_accessed_time.


过期处理:在一个服务器上启动一个定时程序,每隔一段时间从db中得到所有的sessionId,在一个一个的得到期sessionId_last_accessed_time,进行比较,把过期的session从memcached和db中清除.
0 请登录后投票
   发表时间:2008-06-06  
sorphi 写道

使用mysql memory table,我需要在存放item到memcached时设置一个足够长的expire时间,避免因为mysql的故障引起的无法expire那些不存在于memory table中的session。


不需要的,memcached是LRU算法,长时间不访问的cache对象就LRU出去了。
0 请登录后投票
   发表时间:2008-06-06  
neptune 写道
我也有个方案,不知行不行(程序已实现,就是还没有实际用过)

memcached部分
sessionId_attr_names=属性名列表(attr1,attr2)
sessionId_attr1=attr1value
sessionId_attr2=attr2value
sessionId_last_accessed_time=最后访问时间

cookie部分
上一次访问时间(last_accessed_time)

db部分(内存表)
就一个字段sessionId(memcached不支持iterate没什么好办法)

以下如何实现

创建sessionId时,才用db增加sessionId.

增加属性时,需要修改sessionId_attr_names和增加相关sessinId_attr(name)

读取属性时,直接读sessionId_attr(name)

删除属性时,需要修改sessionId_attr_names和删除相关sessionId_attr(name)

要使expire有效,就要使用到last_accessed_time,这里不是每次请求都设置memcached的sessionId_last_accessed_time,这样会对memcached开销太大,在filter中,设置一个"容忍偏差"时间我的设置为5秒,只有在cookie的last_accessed_time + 这个容忍偏差 >当前时间时,才要设置memcached的last_accessed_time.


过期处理:在一个服务器上启动一个定时程序,每隔一段时间从db中得到所有的sessionId,在一个一个的得到期sessionId_last_accessed_time,进行比较,把过期的session从memcached和db中清除.


你的方案不行的,因为你无法保证在操作MySQL和memcached之间保持原子性和事务性。
0 请登录后投票
   发表时间:2008-06-06  
robbin 写道
sorphi 写道

使用mysql memory table,我需要在存放item到memcached时设置一个足够长的expire时间,避免因为mysql的故障引起的无法expire那些不存在于memory table中的session。


不需要的,memcached是LRU算法,长时间不访问的cache对象就LRU出去了。

LRU,可以满足了,我怎么给想成FIFO了



to neptune:
关于实现部分,还没仔细的想,而且我现在只是想先实现CookieStoreProvider。

至于MemcachedStoreProvider,
>>sessionId_attr_names=属性名列表(attr1,attr2)
这个我觉得不妥,试想有属性名就是"attr_names"。再者,sessionId这个key对应的value存放啥?不如就存放属性名列表。

>>sessionId_last_accessed_time=最后访问时间
由于使用mysql memory table,所以最后访问时间就不存储到memcached了。

容忍偏差是个好想法,但是现在我没有想好具体怎么使用。

>>每隔一段时间从db中得到所有的sessionId,在一个一个的得到期..
不建议,使用where access_at<current-expire即可

关于使用自定义结构的Session,如何模拟session的大部分操作和Store的交互,细节问题很多还没考虑。不过最重要的是要解决线程安全的问题。

0 请登录后投票
   发表时间:2008-06-07  
我的解决方案:
1、MemcachedServer 使用类似 RIAD的 0+1 方案
2、定义属性Session_ID为KEY,然后所有的Session属性和最后访问时间为值。
3、取Session_ID 的值,取他的超时时间。决定是否超时,对于session的值,不需要超时时间的。如果超时,直接remove
4、定义一个最外围的Filter,Filter开始的时候从MemcacheServer中取出Session_ID 的值,然后根据Key Gets Session的内容;然后将取得的内容付给Session对象。
5、定义一个属性更新的Listener
6、Filter执行完毕后,根据Listener收集的属性变更,然后对update 、remove的操作维护 Memcache Values,replace Session_ID 的值
7、根据需要,定义个保存Session_ID的桶,定期检查桶的内容是否过期;因为 如果没有参数 —M,Memcache采取的是 LRU算法;所定期检查的时间可以稍长,可以根据状态报告的内容来做,毕竟 过期的内容如果不访问和删除,一直保存在Memcache 中
0 请登录后投票
   发表时间:2008-09-05  
我觉得用timesten比较合适,但是类似于这样内存数据库保存session的话,就是expired的问题比较麻烦,这个需要自己另外写个线程来维护session的过期问题。
0 请登录后投票
   发表时间:2008-09-05  
另外一个如果自己定义session结构,完全放弃容器的session结构,这样的话对于一些开发框架会不会有影响,因为毕竟很多框架象jboss seam的状态机制都是基于标准的http session来管理的,如果是自定义的这时候就麻烦了。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics