实现集群环境下的高可用Session
2015年02月28日


为了支持海量用户的访问,应用服务器集群这种水平扩展的方式是最常用的。在单机环境中,Session的创建和存储都是由同一个应用服务器实例来完成,而存储也仅是内存中,最多会在正常的停止服务器的时候,把当前活动的Session钝化到本地,再次启动时重新加载。

 

而多个实例之间,Session数据是完全隔离的。而为了实现Session的高可用,多实例间session数据共享是必然的。具体来说,常用有以下几种方案:

Ø  会话保持(案例:NginxHaproxy

Ø  会话复制(案例:TomcatWAS

Ø  会话共享(案例:MemcachedRedis

 

一、Session保持(会话保持Session粘滞

 

会话保持方案,在所有的负载均衡中间件上都有对应的实现。通过会话保持,负载均衡在进行请求分发的时候,保证每个客户端固定的访问到后端的同一台应用服务器。这是在负载均衡这一层就可以解决Session问题。

 

先看Nginx的负载均衡的例子,nginxupstream目前支持5种方式的分配方式,其中有两种比较通用的Session解决方法,ip_hashurl_hash。注意:后者不是官方模块,需要额外安装。

 

ip_hash,可以叫做IP粘滞,即每个请求按访问iphash结果固定分配,很简单,这样每个访客也能固定访问一个后端服务器,达到了Session保持的效果。例:

upstream bakend {

   ip_hash;

   server 192.168.0.11:80;

   server 192.168.0.12:80;

 }

 

再看Haproxy的负载均衡的例子:

Ø  源地址 Hashbalancesource

haroxy 将用户IP经过hash计算后指定到固定的真实服务器上(类似于nginx ip hash 指令)

 

Ø  使用cookie 进行识别

也就是Haproxy在用户第一次访问的后在用户浏览器插入了一个Cookie,用户下一次访问的时候浏览器就会带上这个CookieHaproxyHaproxy进行识别。

配置指令:  cookie  SESSION_COOKIE  insert indirect nocache

配置例子如下:

cookie SERVERID insert indirect nocache

server web01 192.168.56.11:8080 check cookie web01

server web02 192.168.56.12:8080 check cookie web02

 

会话保持的缺点:

Ø  负载不均衡了:由于使用了固定的ip hash,像权重分配这样的动态策略已经无法工作,破坏了负载均衡的灵活性。

Ø  没有彻底解决问题:如果后端有服务器宕机,负载均衡把请求路由到其他服务器,那用户在其他服务器上无session信息,仍然需要重新登录。

 

 

二、会话复制

 

就是把Session信息同步给集群上的所有服务器上,例如tomcat支持的,是基于IP多播(multicast),Tomcat的会话复制分为两种:

全局会话复制:利用Delta Manager复制会话中的变更信息到集群中的所有其他节点

非全局复制:使用Backup Manager进行复制,它会把Session复制给一个指定的备份节点

 

另外,像一些企业级应用服务器,WASJBOSS,在集群上的支持会更好一些,session复制也更高效和可靠。

 

但是总的来说,会话复制理念,还是不够高效,而且只能用于相同类型的服务器之间,而且session内容是基于java io的序列化方式保存,性能消耗很大。总之,会话复制,不适合大的集群和复杂网络环境,所以不过多介绍。

 

 

三、会话共享

 

会话复制的效率,赶不上会话集中单独管理,即集群中所有服务器都在同一个地方去拿Session信息,这样也更专业一些。

 

Session集中存放到哪里?

对于Session来说,肯定是频繁使用的,虽然你可以把它存放在数据库中,但是真正生产环境中一般推荐存放在性能更快的分布式KV数据中,例如:MemcachedRedis

 

Tomcat等一些服务器,都支持扩展一些插件,自动把session信息保存到MemcachedRedis缓存中。对于Tomcat,我们可以使用MSMMemcached Session Manager)来实现把Session存放到Memcache中,Github地址如下:https://github.com/magro/memcached-session-manager目前支持Tomcat 6.x7.x8.x的版本。

如果你想使用Redis,刚好也有开源的可以用,但是遗憾的是暂时不支持Tomcat 8.x的版本:https://github.com/jcoleman/tomcat-redis-session-manager

 

Tomcat保存session到缓存的原理参见:

详解集群内Session高可用的实现原理