SpringSession 初步了解

来源:互联网 发布:大麦户源码下载 编辑:程序博客网 时间:2024/05/01 22:45

         为支持项目的分包部署,简化分包环境下的SSO和Session共享,首次在架构中引入了SpringSession的SNA组件,为此项目组进行了不少工作,包括:Spring平台从原来的Spring2.5.6一跃到Spring4,同时引入了SpringSession所必须的SpringData和对Redis的支持。

         SpringSession的原理其实很简单:就是通过一个站在最顶端的Filter,将传统的HttpServletRequest和HttpServletResponse进行包装,重载getSession方式,将获取和存储Session的相关操作,转义到保存或者从Redis中提取信息。由于Redis支持Map形式的数据类型,因此比较适合存储Session这类数据,选用Redis作为集中缓存也就顺理成章了。

         从Redis3.0版本开始,Redis内存库自身已经支持集群管理,我们可以方便地创建出一个多主多备的Redis集群环境。并且SpringSession目前的版本已经是1.3.1,从版本上看,也具备使用价值了。

         前段时间为检验SpringSession的性能,进行了几轮对比压力测试,发现使用SpringSession的分包环境比较慢,我们非常重视这件事情,要分析和性能调优,首先要弄清楚SpringSession到底是怎么做的。只能通过读源码了。真的很佩服Spring的设计师,程序还是一如既往的“复杂”,但结构非常清晰,设计师还是非常有水准的。通过源码和Redis的活动监控,也发现了SpringSession处理的一些端倪。

         SpringSession对Redis的封装完全基于Jedis,连接池也是使用的Apache的Commons-Pool,借助SpringData进行统一封装。使用了Spring惯用的FilterProxy机制,使用一个Filter完成了对Request,Response的Wrap。并在Wrap中完成Session信息向Redis的双向转移。

         为了提高效率,SpringSession中对Session做了特殊的处理:

1)  每次从Redis中获取信息以后,在RequestContext中进行了缓存,因此一次请求只需从Redis中读取一次。

2)  对于Session信息的保存时机,SpringSession提供了两种方案供你选择:Immediate和ON_SAVE,分别为马上保存和批量保存。

3)  对于保存的信息,SpringSession进行的增量处理,即在Session的本地缓存中,包有一个记录Session变化的Delta,每次进行保存时只需要处理变化的量。

 

还有一个棘手的问题是:关于超时如何处理,采用SpringSession机制后,Web中的一些规范,如SessionListner机制将会变得很复杂,因此SpringSession为此做了很多的工作。

1)  为保存在Redis中的Session信息设置了超时时间,为了保证这种机制的顺利进行,除了Session信息,SpringSession在Redis中还维持着多个key和集合:包括:单独增加了一个key,记录Session的超时时间,可以借助Redis的通知机制完成;为了保证超时的信息能及时删除,SpringSession还位置着一个到期的Collection,定时检查这个集合,主动进行Session超时处理。这部分比较复杂,这里不多讲了。

2)  每次请求,SpringSession都会更新Session和上述附件信息的超时时间,显得非常啰嗦

性能差的原因会不会是Redis访问太频繁造成的呢?我们单独跟踪了一个请求,发现SpringSession采用增量方式进行了两次保存 HMSet,通过仔细分析代码,发现在ResponseFlush 之前,为保证Response中保持Cookie信息,执行了一次增量保存,最后Filter执行完了后,在finally方法中又执行了一次。分析程序发现每执行一次,要访问Redis多次,达到保存、更新和设置超时时间的目的。我们遇到的一个问题是:根据SpringSession的保存策略,只要Delta中没有变更信息,系统不再保存,进而也没有相关的设置超时时间的动作,为什么我们系统在Finally中也进行了保存呢?根据Redis的监控结果,发现平台中的一个Filter在执行完DoFilter后,在Session中设置了一个值,引起了Delta的变化,从而触发了finally方法中的save操作

 

           要使用SpringSession+Redis,有几件事情要注意:

1)  应该在一个网段中,保证网络的带宽

2)  需要修改程序,将Session中的信息变得简单,最好只保留用户和授权信息

3)  作为信息传递的Session信息,使用完毕后,尽快删除

4)  系统中的Filter中蛮实用Session时要注意,尽量让SpringSession保存一次Session信息。

5)  有可能的话,对SpringSession的超时机制进行优化,减少不必要的处理。这个相对麻烦一些,我们现在只能通过硬编码的方式,没有一种优雅的替换策略。

0 0
原创粉丝点击