我发现了一个商城,我尚未登陆,就能够往购物车中添加商品,加了好几件后,我准备付款,须要我先去登陆,登陆完以后付款。html
如今不少商城,都会要求用户先去登陆,登陆以后再往购物车中添加商品,这样用户、购物车、商品,三个对象之间就有了绑定关系。java
而针对我最开始说的那种状况,其实就是基于session
作的,客户端往购物车中添加第一个商品的时候,发送一个请求,服务到收到请求以后,建立session
,而后返回当前session
对应的一个JessionId
,浏览器存储在cookie
中,客户端往购物车添加第二个商品时,携带JessionId
,服务端收到请求后,更新session
。浏览器关闭后,cookie
失效,JessionId
也就丢失了,须要从新往购物车中添加商品,默认状况下,session
有效期为30
分钟。mysql
在分布式环境下,session
就会出现问题了,假如服务端部署在两个服务器A
和B
上。第一次往购物车添加商品时,请求落在了服务器A上,服务器A建立了一个session
,并返回JessionId
,第二次往购物车添加商品时,请求落在了服务器B上,请求携带的JesssionId
在服务器B上并不会找到对应的session
。这时候服务器B就会建立一个新的session
,并返回对应的JessionId
,客户端发现第一次添加的商品丢失了。。。web
接下来,一块儿来学习分布式环境下session
一致性是如何实现的。面试
既然分布式环境中,一个客户端的多个请求可能会落在多个服务器上,那么咱们是否能够改不策略,直接将session信息存储在客户端?能够的,服务器将session信息直接存储到cookie中,这样就保证了session的一致性,可是并不推荐这样去作,由于将一些信息存储在cookie中,至关于就把这些信息暴露给了客户端,存在严重的安全隐患。redis
缺点:spring
将服务器A的session,复制到服务器B,一样将服务器B的session也复制到服务器A,这样两台服务器的session就一致了。像tomcat等web容器都支持session复制的功能,在同一个局域网内,一台服务器的session
会广播给其余服务器。sql
缺点:mongodb
同一个网段内服务器太多,每一个服务器都会去复制session,会形成服务器内存浪费。apache
利用Nginx
服务器的反向代理,将服务器A和服务器B进行代理,而后采用ip_hash
的负载策略,将客户端和服务器进行绑定,也就是说客户端A第一次访问的是服务器B,那么第二次访问也必然是服务器B,这样就不存在session不一致的问题了。
缺点:
若是服务器A宕机了,那么客户端A和客户端B的session就会出现丢失。
这种方式就是将全部服务器的session
进行统一管理,可使用redis
等高性能服务器来集中管理session,并且spring官方提供的spirng-session
就是这样处理session
的一致性问题。这也是目前企业开发用到的比较多的一种分布式session
解决方案。
Spring
提供了处理分布式session的解决方案——Spring Session
。Spring Session
提供了用于管理用户会话的API和实现。
Spring Session
提供了对redis
,mongodb
,mysql
等经常使用的存储库的支持,Spring Session
提供与HttpSession
的透明整合,这意味着开发人员可使用Spring Session支持的实现切换HttpSession
实现。仍是原来的配方,产生了不同的味道!
Spring Session
添加了一个SessionRepositoryFilter
的过滤器,用来修改包装请求和响应,包装后的请求为SessionRepositoryRequestWrapper
,调用getSession()
方法的时候实际上就是调用Spring Session
实现了的session。
Spring Session
使用很是简单,添加了相关依赖后,直接操做HttpSession
就能够实现效果。
第一步:添加Spring Session
和 redis
的相关依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
第二步:配置redis相关信息
spring: redis: # redis库 database: 0 # redis 服务器地址 host: localhost # redis 端口号 port: 6379 # redis 密码 password: # session 使用redis存储 session: store-type: redis
第三步:项目中使用session
public String sessionTest(HttpServletRequest request){ HttpSession session = request.getSession(); session.setAttribute("key","value"); return session.getAttribute("key").toString(); }
redis
中每一个session存储了三条信息。
处理一个session为何要存储三条数据,而不是一条呢!对于session的实现,须要监听它的建立、过时等事件,redis能够监听某个key的变化,当key发生变化时,能够快速作出相应的处理。
可是Redis中带有过时的key有两种方式:
当访问时发现其过时,会产生过时事件,可是没法保证key的过时时间抵达后当即生成过时事件。
spring-session为了可以及时的产生Session的过时时的过时事件,因此增长了:
spring:session:sessions:expires:726de8fc-c045-481a-986d-f7c4c5851a67
spring:session:expirations:1620393360000
spring-session中有个定时任务,每一个整分钟都会查询相应的spring:session:expirations:整分钟的时间戳中的过时SessionId,而后再访问一次这个SessionId,即spring:session:sessions:expires:SessionId,以便可以让Redis及时的产生key过时事件——即Session过时事件。
https://www.cnblogs.com/sxw12...
若是以为文章不错,欢迎关注、点赞、收藏,大家的支持是我创做的动力,感谢你们。
若是文章写的有问题,请不要吝惜文笔,欢迎留言指出,我会及时核查修改。
若是你还想看到更多别的东西,能够微信搜索「Java旅途」进行关注。回复“手册”领取Java面试手册!