在分布式环境中,浏览器端发送的请求经负载均衡后分配到不同的服务器,因此存在session无法共享的问题。
解决方案有如下几种
方案一:客户端存储
即将信息存储在cookie中。
由于cookie是存储在客户端浏览器中的,存在一些安全隐患,而且cookie的存储大小和类型存在限制,只能存储少量数据。
方案二:服务器session复制
Session复制是小型企业使用比较多的一种服务器集群session管理机制。它的原理是,一个服务器上的session发生变化,则广播到局域网内其他服务器上进行同步,这样所有的服务器上的session都是同步的,任何一台服务器宕机的时候,都可以从其他服务器上获取到session,不会影响业务功能。
缺点:会对网络负荷造成一定压力。当session量比较大时,可能会造成网络阻塞,拖慢服务器性能。
配置:Tomcat内部已经支持分布式框架开发管理机制,修改Tomcat安装目录下config目录下的配置文件server.xml,支持集群部署。同时在应用中修改web.xml文件,开启session复制。
server.xml
方案三:session绑定
Nginx是一款高性能的http服务器和反向代理服务器,它可以做正向代理、负载均衡、http服务器和反向代理。Nginx默认使用轮训机制,将客户端请求负载均衡地分配到不同的服务器,因此来自同一个客户端的不同请求可能会被分配到不同的服务器,这样就无法获取到之前存储的session。
除了轮训机制,Nginx还有ip_hash机制进行负载均衡,即根据ip进行分配,将客户端和服务器进行绑定,来自同一个客户端的请求会被指定分配到固定的服务器上。
缺点:缺乏容错性,如果当前访问的服务器出现故障,请求被转移到其他服务器,则之前的session都将失效。
配置:在Nginx的配置文件中,在upstream模块指定使用ip_hash模式。
方案四:使用redis存储session
在分布式项目,大多都会使用Redis做缓存,而且Redis还可以集群部署,天然支持数据共享。因此将session存储到Redis中无缝接入,不存在任何安全隐患,是目前企业中使用最多的一种方式。Spring为我们封装了spring-session框架,直接引入依赖即可。
基于redis存储session方案流程示意图
pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-data-starter-redis</artifactId>
</dependency>
Redis配置
#redis数据库索引(默认是0)
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
#默认密码为空
spring.redis.password=
#连接池最大连接数(负数表示没有限制)
spring.redis.jedis.pool.max-active=1000
#连接池最大阻塞等待时间(负数表示没有限制)
spring.redis.jedis.pool.max-wait=-1ms
#连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
#连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=2
#连接超时时间(毫秒)
spring.redis.timeout=500ms
方案五:session持久化到数据库
将服务器端的session持久化到数据库中,这样所有的服务器都可以去数据库中获取session。但是如果服务器访问量很大,会对数据库造成很大的压力。其次每次访问数据库效率也不高。