使用redis实现自己的tomcat session manager(java)

使用redis实现自己的tomcat session manager(java)

最近业务扩展到了好几个tomcat,前端使用nginx,rewrite的规则设置为ip_hash,但这样如果有一个tomcat挂了,那这个用户就要重新登陆了,本来也可以忍受,但这说来说去总是一个问题,于是自己决定实现一个自己的session manager,所有的用户的session都保存到这个session manager上,获得session就到这个服务器上去获取,当session变化之后就重新把session保存到服务器上。嗯,大概就是这样。

从网上找到了一个这样的开源项目:https://github.com/jcoleman/tomcat-redis-session-manager。这个工程用在tomcat上的,基本原理是重新实现了tomcat的manager接口,使得所有的session的访问都指向redis服务器。然后部署的时候只要把相应的jar包拷贝到tomcat的lib目录,然后修改conf中的context.xml配置文件就可以了,对web应用完全透明。真是一个非常优雅的实现。所以我就以这个工程作为自己的session manager实现的基础。

这个工程使用和测试之后发现了不少问题。下面总结一下:

  1. 保存在session中的对象必须实现serializable接口,并且必须有默认构造函数
  2. 使用了java的序列化,速度比较慢
  3. 如果保存规则设置为default,那么每次都需要把整个session序列化为byte数组然后获得摘要去比较session是否变化,速度慢。

好,发现了开源工程的问题,那么我们就来修改一下。使用kryo序列化库来代替java本身的序列化,这样速度会有明显的提升,并且对象不需要有一个默认的构造函数。然后删除摘要比较的代码,只需要通过dirty标志来判断是否保存到redis,这样做需要代码配合才能保证正确性,比如session中保存了一个list,然后list中add了几个元素,这样由于list没有变化,所以manager会判断session没有变化然后不保存,就错了,所以需要代码主动标志这个session是dirty的,一行代码就可以:

session.setAttribute("__changed__");

实现过程中发现了几个很有意思的问题,这里记录一下:

kryo库解序列化出现classnotfound exception

这个问题比较有意思,牵扯到tomcat的classloader的机制,对于理解tomcat的classloader是一个非常好的例子。具体原因是这样的:tomcat的lib目录下的库都是standardclassloader加载的,但是每个webapp都会有自己的classloader,类型是webappclassloader,这里二者的关系是webappclassloader的parent是standardclassloader。记住这些。下面分析原因。

由于部署redis session manager是把库拷贝到lib目录下,那么kryo的classloader就是standardclassloader,但是session中保存的对象是webapp下的lib目录下的某个class,是由webappclassloader加载的,standardclassloader是不可能找到webappclassloader加载的类的class对象的,所以抛出异常。

解决办法:
把kryo库中的class.forName方法中的classloader修改为当前线程上下文的classloader。tomcat中线程的上下文的classloader是webappclassloader,这样就可以加载某个webapp的类了。

not arg constructor method error

还是kryo的解序列化的错误,说没有找到一个默认的构造函数。

解决办法:kryo库不需要一个默认构造函数,如果没有默认构造函数,它会使用java底层方法使用字节码构造对象。需要使用下面的代码开启这项功能:

kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));

结论

修改后的manager性能比原来的高了大约40%左右。代码放在github上,有兴趣的可以去下载使用。
https://github.com/longlong524/redis_session_manager

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值