锁定老帖子 主题:SNA方案之session store调研
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间: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。很重量级,这里不表。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-06-05
用mysql memory table的话,你就可以iterate了。不过mysql memory table有一个缺陷,内存分配的浪费很严重,ebay有一个工程师写了一个patch在很大程度上解决了这个问题,还获了mysql年度的奖,他的patch在这里:
http://code.google.com/p/mysql-heap-dynamic-rows/ |
|
返回顶楼 | |
发表时间: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。 |
|
返回顶楼 | |
发表时间: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中清除. |
|
返回顶楼 | |
发表时间:2008-06-06
sorphi 写道 使用mysql memory table,我需要在存放item到memcached时设置一个足够长的expire时间,避免因为mysql的故障引起的无法expire那些不存在于memory table中的session。 不需要的,memcached是LRU算法,长时间不访问的cache对象就LRU出去了。 |
|
返回顶楼 | |
发表时间: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之间保持原子性和事务性。 |
|
返回顶楼 | |
发表时间: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的交互,细节问题很多还没考虑。不过最重要的是要解决线程安全的问题。 |
|
返回顶楼 | |
发表时间: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 中 |
|
返回顶楼 | |
发表时间:2008-09-05
我觉得用timesten比较合适,但是类似于这样内存数据库保存session的话,就是expired的问题比较麻烦,这个需要自己另外写个线程来维护session的过期问题。
|
|
返回顶楼 | |
发表时间:2008-09-05
另外一个如果自己定义session结构,完全放弃容器的session结构,这样的话对于一些开发框架会不会有影响,因为毕竟很多框架象jboss seam的状态机制都是基于标准的http session来管理的,如果是自定义的这时候就麻烦了。
|
|
返回顶楼 | |