Skip to the content.

[TOC]

分布式Session

小时候,我们的网站还是萌芽期,用户少、访问量少、流量小,一台机器就足以应对。如今,互联网的爆发,经济的发展,有了大量用户涌入网站,我们的网站开始崩溃,时不时宕机,于时,机智的程序猿们、运维界的大佬们,整出了集群,这下解决了单机应用的瓶颈,但是紧接着问题又来了,单机的Session、事务、锁等等,在应用集群部署的情况下,全部遇害,怎么办呢,那么今天我们就谈谈单机Session如何在集群部署中做到分布式。

一、常见的实现方式

A、粘性Session

何为粘性,顾名思义,把Session和客户端粘起来。

例如:最常见的利用Nginx的负载均衡策略IpHash,原理将客户端的IP和Nginx反向代理的服务器做一对一的绑定,当客户端第一次访问进来,请求被Nginx代理,转发给了服务器A,后续该客户端的请求(IP不变)一直会转发给服务器A。

B、服务器Session同步

服务端各自将自己管理的Session产生的任何变化,通过指定端口广播出去,集群里其他机器在收到广播信息后,及时对自己的Session做响应的变更。

例如:通过对Tomcat的Server.xml进行节点的相关配置,指定address和port,那么Tomcat在自己管理的Session发送变更时,将会将变更的消息通过这个IP和端口广播出去,同时各应用的web.xml要做好配置,告诉容器当前应用处于集群环境。

C、Session持久化到数据库

这种实现方式没什么争议,通过重写(非)原生的Session管理,即可将Session的创建、获取等持久化到DB去,至于DB各自想用哪种就可以用哪种。

D、利用缓存中间件做到Session共享

有人说缓存中间件也可以做到粘性和非粘性的,下面我就来说说:

  1. 粘性Session处理方式

    每个应用在储存Session的同时,会将创建的Session备份到缓存中间件,实际客户端和每个应用还是绑定,负载均衡固定分发请求,当其中一台应用宕机后,客户端请求才会被分配到下一台应用,此时客户端无法命中新应用内存中的Session,而新应用在找不到客户端的Session时,还会去缓存中间件找,如果找到,则复制到自己的内存来,反之,重新在自己的内存中创建Session,再将Session备份到缓存中间件中,以此,重复以上过程。

  2. 非粘性Session处理方式

    这种方式与上面的方式完全不一样,为什么呢,因为每个应用不会在自己的内存中管理Session,所有关于Session的创建、获取等操作,都直接在缓存中间件上操作。

关于以上两种方式,怎么说呢,如果不是特别的需要,我推荐直接实现第二种方式即可,第一次方式很明显多了很多查询、存储操作。

E、Terracotta实现session复制

Terracotta,这是个啥,百度百科描述为Java集群平台(JVM级别),简介是,允许用户不改变现有系统代码的情况下实现单机应用向集群化应用的无缝迁移。这么一讲大致明白了,原本是单机管理的内存数据,引入Terracotta后,可以将单机管理的内存数据,同步到集群中的其他机器中去。相对于Tomcat的Session广播机制,Terracotta的优点是广播的消息只会被需要此消息的对象接收到,这样会稍微降低些网络压力。

二、到底哪个好

方式 优点 缺点
粘性Session 应用无需任何修改 缺乏容错性,一旦某个应用重启,带来的将是一整个应用的Session丢失
服务器Session同步 单个应用宕机,不会导致Session丢失 大量的Session广播到占用网络带宽,影响正常请求
Session持久化到数据库 稳定性高,不会因为应用的宕机而丢失Session 对磁盘IO、网络带宽等产生一定的负荷,大量Session的创建和读取,可能导致数据库响应迟钝
利用缓存中间件做到Session共享 可容错,应用的增加和减少,不会对Session的数据产生任何影响  
Terracotta实现session复制 对网络的压力就非常小,各个节点也不必浪费CPU时间和内存进行大量的序列化操作。把这种集群间数据共享的机制应用在session同步上,既避免了对数据库的依赖,又能达到负载均衡和灾难恢复的效果  

三、总结

就实际生产案例中,还是将Session的管理直接迁移到缓存中间件中,是较为稳妥的,至于是重写原生的Sesion管理方式,还是依托Apache Shiro重写SessionDao,又或者是直接依赖Spring Session来的更快些,这些就看各位大神大显神通了。

##