Session简介
HTTP是一种无状态协议,所以当客户端发起多次请求时,服务器是无法识别请求是否来自同一个用户;在一些业务场景中我们系统需要知道前后操作是否为同一个用户的行为,此时为了保证数据传输的安全性,我们就会使用session来保存用户信息等,Session在网络中表示“会话控制”,用于服务端存储特定用户所需的属性和其他的配置信息。一般在实际项目中我们采取Session结合浏览器Cookie方式,当浏览器发起请求到Tomcat服务器,然后Tomcat服务器生成SessionId保存在内存中,并将SessionId返回给浏览器,浏览器通过Cookie保存SessionId信息,用户每次通过浏览器访问服务器都会带上SessionId信息,这样就可以判断每次的请求是不是同一个用户,用于解决HTTP协议无状态问题~
Session共享
问题:如今随着信息化不断发展,越来越多的的公司根据业务不断扩展逐步采用分布式架构,当分布式使用Nginxt实现负载均衡,Nginx会针对不同的请求分发到某一个Tomcat,而不同的tomcat 服务器中的session是不同的,因此会出现Session不同步或者丢失的问题。如何保证不同的Web站点能够共享同一个Session数据呢?
方案一:客户端存储(即浏览器cookie存储)
客户端浏览器自己来存储session,服务器从每次请求中读取浏览器带过来的cookie,这样可以节省服务器资源
缺点:
- 每次http请求,携带用户在cookie中的完整信息,浪费网络带宽
- session数据放在浏览器的cookie中,有些浏览器遵循的标准不一样,它的长度限制不一样,比如长度限制4k,因此不能保存大量信息
- session数据放在cookie中,存在泄露、篡改、窃取等安全隐患
针对如上缺点我们项目中不会使用这种cookie存储会话数据方案
方案二:第三方数据库统一存储(推荐)
在分布式场景下,浏览器访问我们服务的时候,由于负载均衡机制会跳到不同的服务器,而又由于session是每个服务器各自存储在各自内存空间的,所以这导致我们跳到下一个服务器以后,我们上一个服务器session里面的数据它就用不到了,所以我们可以采取session统一存到关系数据库或者redis这种内存数据库中
- 优点
- 无安全隐患,只要我们保障了我们后台的redis的安全,就没有人能去篡改里面相关的数据
- 易于水平扩展,无论web服务器增加多少个都去redis中做存取,即使redis不够用,我们也可以做redis集群提升效率
- session不会丢失,服务器重启、宕机,也不会导致session丢失,因为session都是存储在redis中
- 缺点
- 增加了网络开销,因为原先从内存中取数据是非常快的,也不需要网络交互,但存储在redis中我们就需要通过网络交互连接redis
- 修改应用代码:如将所有的getSession方法替换为从Redis查数据的方式
目前比较流行的方案是通过Spring提供的Spring-Session框架管理session数据,通过spring-session-data-redis去对redis进行读写操作,较为完美的解决我们session统一存储问题~