为了提高服务器性能,最近公司项目采用了分布式服务集群的部署方式。所谓集群,就是让一组计算机服务器协同工作,解决大并发,大数据量瓶颈问题。项目使用nginx做负载均衡,这样同一个IP访问同一个页面会被分配到不同的服务器上,此时就涉及到一个session共享的问题。因为session是在服务器端保存的,如果用户跳转到其他服务器的话,session就会丢失,一般情况下,session不可跨服务器而存在。于是就有了分布式系统的session共享问题。
集群中session安全和同步是个最大的问题,下面是收集到的几种session同步的方案,希望能通过分析其各自的优劣找出其适应的场景。
一、客户端cookie加密
当用户登陆成功以后,把网站域名、用户名、密码、token、 session有效时间全部采用cookie的形式写入到客户端的cookie里面。如果用户从一台Web服务器跨越到另一台服务器的时候,我们的程序主动去检测客户端的cookie信息,进行判断,然后提供对应的服务,当然,如果cookie过期,或者无效,自然就不让用户继续服务了。
优点:
简单、高效,也不会加大数据库的负担。
缺点:
- cookie安全性较低,虽然它已经加了密,但是还是可以伪造的。
- 但是如果客户端把cookie禁掉了的话,那么session就无从同步了,这样会给网站带来损失;
- session中数据不能太多,最好只有个用户id。
二、session复制
大部分应用服务器都提供了session复制的功能来实现集群,tomcat,jboss,was都提供了这样的功能。
优点:
通过应用服务器配置即可,无需改动代码。
缺点:
- 性能随着服务器增加急剧下降,而且容易引起广播风暴;
- session数据需要序列化,影响性能。
三、使用数据库保存session
这种共享session的方式即将session信息存入数据库中,其它应用可以从数据库中查出session信息。
优点:
使用数据库来保存session,就算服务器宕机了也没事,session照样在。
缺点:
- 每次请求都需要对数据库进行读写,session的并发读写在数据库中完成,会加大数据库的IO,对数据库性能要求比较高。
- 我们需要额外地实现session淘汰逻辑代码,即定时从数据库表中更新和删除session信息,增加了工作量。
- 数据库读写速度较慢,不利于session的适时同步。
四、使用redis或memcache来保存session
提供一个集群保存session共享信息,其他应用统统把自己的session信息存放到session集群服务器组。当应用系统需要session信息的时候直接到session群集服务器上读取。目前大多都是使用Memcache或redis来对Session进行存储。以这种方式来同步session,不会加大数据库的负担,并且安全性比用cookie大大的提高,把session放到内存里面,比从文件中读取要快很多。
以redis来实现Session共享的方式目前比较流行的有两种实现方案,下面主要对这两种方案进行介绍。
1. tomcat-cluster-redis-session-manager
使用 tomcat-redis-session-manager 开源项目解决分布式session跨域的问题,他的主要思想是利用Servlet容器提供的插件功能,自定义HttpSession的创建和管理策略,并通过配置的方式替换掉默认的策略。tomcat-redis-session-manager
重写了Tomcat的org.apache.catalina.session.ManagerBase
里边的具体写的操作, 将tomcat的session存储位置指向了Redis:
RedisSessionManager
继承了org.apache.catalina.session.ManagerBase
并重写了 add
、findSession
、createEmptySession
、remove
等方法,并将对session
的增删改查操作指向了对Redis数据存储的操作。
具体可以参考:Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享
优点:
无需修改任何代码。
缺点:
- 配置相对还是有一点繁琐,需要人为的去修改Tomcat的配置。
- 暂时此插件只支持tomcat7、tomcat8、tomcat9,对于tomcat有较大的依赖。
2. 使用Spring Session和redis管理session
Spring Session不依赖于Servlet容器,而是Web应用代码层面的实现,直接在已有项目基础上加入spring Session框架来实现Session统一存储在Redis中。如果你的Web应用是基于Spring框架开发的,只需要对现有项目进行少量配置,即可将一个单机版的Web应用改为一个分布式应用,由于不基于Servlet容器,所以可以随意将项目移植到其他容器。
优点:
- 如果web应用是基于spring框架开发的,那么只需简单配置,既可以修改为一个分布式应用。
- 不急于servlet容器,可以随意将项目移植到其他容器。
缺点:
需要修改代码。
具体可以参考:使用Spring Session和Redis解决分布式Session跨域共享问题
参考链接: