当前位置: 首页 > 科技观察

分布式Session的几种方案,你喜欢哪一种?

时间:2023-03-15 23:15:12 科技观察

我找到了一个商场。我可以在不登录的情况下将商品添加到购物车。添加几件商品后,我就可以付款了。需要先登录,登录后支付,现在很多商城都要求用户先登录,登录后才能将商品添加到购物车,这样用户、购物车、商品就形成了绑定关系三个物体之间。对于我一开始提到的情况,其实是基于session的。当客户端将第一个项目添加到购物车时,它会发送一个请求。服务端收到请求后创建session并返回当前session对应浏览器在cookie中保存一个JessionId,当客户端添加第二个商品到购物车时携带JessionId,服务端更新session收到请求后。浏览器关闭后cookie失效,JessionId丢失。您需要重新将商品添加到购物车。默认情况下,会话有效期为30分钟。在分布式环境下,session会出现问题,如果服务器部署在A和B两台服务器上,第一次添加商品到购物车时,请求落在A服务器上,A服务器创建session,返回JessionId。第二次向购物车添加商品时,请求落在了B服务器上,请求中携带JesssionId的请求不会在B服务器上找到对应的session,此时B服务器会新建一个session,并返回对应的JessionId。客户发现第一次添加的产品丢失了。..接下来,让我们学习如何在分布式环境中实现会话一致性。1.客户端存储由于在分布式环境中,一个客户端的多个请求可能会落在多个服务器上,我们是否可以改变策略,将会话信息直接存储在客户端上呢?是的,服务端直接将session信息保存在cookie中,这样可以保证session的一致性,但是不推荐这样做,因为将一些信息保存在cookie中,就相当于把这些信息暴露给客户端,客户端有严重的安全隐患。缺点:存在安全问题。Cookies对数据类型和数据大小有限制。2.会话复制将服务器A的会话复制到服务器B,同时也将服务器B的会话复制到服务器A,使两台服务器的会话一致。tomcat等Web容器支持session复制的功能。在同一个局域网内,一台服务器的会话会广播到其他服务器。缺点:同一网段的服务器过多,每个服务器都会复制session,造成服务器内存浪费。3、会话粘性使用Nginx服务器的反向代理代理服务器A和服务器B,然后使用ip_hash加载策略绑定客户端和服务器,也就是说客户端A第一次访问的是服务器B,然后第二次访问也一定是服务器B,所以不存在session不一致的问题。缺点:如果服务器A宕机,客户端A和客户端B的会话将丢失。4、集中会话管理这种方式是对所有服务器的会话进行统一管理。可以使用redis等高性能服务器来集中管理session,spring官方提供的spring-session就是这样处理session一致性问题的。这也是目前企业开发中使用的分布式会话方案。五、spring-session实战Spring提供了一个处理分布式会话的方案——SpringSession。SpringSession提供了用于管理用户会话的API和实现。SpringSession提供了对redis、mongodb、mysql等常用存储库的支持。SpringSession提供了与HttpSession的透明集成,这意味着开发者可以将HttpSession的实现与SpringSession支持的实现进行切换。还是原来的配方,做出不一样的味道!SpringSession增加了一个SessionRepositoryFilter过滤器来修改封装请求和响应。打包请求为SessionRepositoryRequestWrapper。在调用getSession()方法时,实际上是在调用SpringSession实现的session。SpringSession使用起来非常简单。添加相关依赖后,直接操作HttpSession即可达到效果。第一步:添加SpringSession和redis的相关依赖org.springframework.sessionspring-session-data-redisorg.springframework.bootspring-boot-启动器-data-redisorg.apache.commonscommons-pool2第二步:配置redis相关信息spring:redis:#redis库database:0#redis服务器地址host:localhost#redis端口号port:6379#redis密码password:#session使用redis存储session:store-type:redis第三步:在项目中使用sessionpublicStringsessionTest(HttpServletRequestrequest){HttpSessionsession=request.getSession();session.setAttribute("key","value");returnsession.getAttribute("key").toString();}Redis中的每个会话存储三条信息。第一个存放session的id,是一个Set类型的Redis数据结构。这个k中的最后一个值1439245080000是一个时间戳,是根据session过期时间滚动到下一分钟计算的。第二个用于存放Session的详细信息,包括session过期时间间隔、最近访问时间、属性等。这个k的过期时间是Session的最大过期时间+5分钟。如果默认最大过期时间是30分钟,那么这个k的过期时间就是35分钟。第三个用于指示Redis中的Session到期。这个k-v不存储任何有用的数据,只是为了表明Session已经过期而设置的。Redis中这个k的过期时间就是Session的过期时间间隔。为什么我们在处理一个session的时候需要存储三份数据而不是一份呢?对于一个session的实现,需要监听它的创建、过期等事件。Redis可以监听某个key的变化。当按键发生变化时,能迅速做出相应的反应。处理。但是Redis中有过期key的情况有两种:访问时发现key过期,Redis后台会逐步搜索过期key。.为了能够及时在Session过期时产生过期事件,spring-session增加了:spring:session:sessions:expires:726de8fc-c045-481a-986d-f7c4c5851a67spring:session:expirations:1620393360000spring-session有定时任务,每整分钟会在对应的spring:session:expirations:整分钟时间戳中查询过期的SessionId,然后再次访问SessionId,即spring:session:sessions:expires:SessionId,以便Redis及时产生key过期事件——即Session过期事件。参考https://www.cnblogs.com/sxw123/p/13803478.html本文转载自微信公众号“Java之旅”,可通过以下二维码关注。转载本文请联系Java之旅公众号。