使用Spring Reactive进行会话管理

在这篇文章中,我们将研究应用程序中会话管理背后的概念,以及如何将这些想法应用于您的代码。

某些Web应用程序需要存储状态,这可以通过使用会话来完成。

这个想法是用户的体验不是由会话管理技术的选择决定的。

Web应用程序通常位于负载均衡器后面,负载均衡器以循环方式发送请求(假设所有服务器具有相同的容量) - 顾名思义 - 平衡负载。

以下是对Web应用程序进行负载平衡的常用方法。

使用Spring Reactive进行会话管理

鉴于上述情况,我们将研究处理用户会话的一些方法。

粘性会话

当用户访问Web应用程序时,负载均衡器会将请求发送到其中一个服务器,在该服务器上创建会话,该会话驻留在服务器本身上。

因此,如果用户的第一个请求被发送到服务器1,则会话在服务器1上创建。如果第二个请求也发送到服务器1,则会找到用户的会话,他们可以继续他们正在做的事情,但是,如果第二个请求被发送到服务器2,然后创建一个新会话,导致用户从头开始。这导致用户具有两个不同的会话(每个服务器上一个),负载均衡器向两个服务器发送请求,从而导致混乱的用户体验。

通过将负载均衡器始终发送到创建它的完全相同的服务器,可以使用粘性会话来避免这种不期望的情况。

优点

  • 由于在负载均衡器上进行了配置,因此无需应用程序代码。

缺点

  • 导致服务器之间负载分布不均匀。
  • 如果服务器出现故障,则该特定服务器上的所有用户都将丢失其会话,并且必须在下一个可用服务器上重新开始。

客户端会话管理

在这种情况下,会话状态存储在cookie中的客户端(您的Web浏览器)上。

由于会话不驻留在服务器上,因此不需要粘性会话,并且由于每个请求将以cookie的形式提供会话,因此您发送到哪个服务器也无关紧要。

可以在Play框架中找到客户端会话管理的示例,其中会话存储在签名cookie(JWT)中并添加到每个后续请求中。

Spring Session不提供客户端会话管理解决方案。有关详细信息,请参见此处

优点

  • 无需在服务器上管理状态。
  • 无需跨服务器复制状态。
  • 更容易扩展。

缺点

  • 限制您可以存储多少数据(最多4KB)。
  • 需要确保会话数据不会被篡改。

服务器端会话管理

如前所述,管理服务器端会话的一种方法是使用粘性会话。

需要粘性会话,因为会话驻留在实际服务器上。

粘性会话方法的几种替代方法:

  1. 将会话存储在Redis,Hazelcast或数据库等支持存储库中。这样,请求结束的服务器将转到后备存储库以获取会话状态。Spring Session是一个开始了解这种方法的好地方。
  2. 跨Web服务器复制会话。在这种情况下,会话仍然驻留在服务器上,但如果一个服务器要关闭,那么会话可以被另一个正在运行的服务器拾取,因为它已被复制。春季会议Hazelcast是了解这种方法的好地方。

优点

  • 只有会话ID公开给客户端。
  • 会话大小没有限制。
  • 可以切换会话状态实现(例如从DB到Redis)。

缺点

  • 运行集群或数据库的开销更大。

Spring Webflux中的会话聚类

Spring Webflux提供WebSession而不是HttpSession。

在春季会议文档提供了Redis的支持,但如果你不想保持的Redis集群的开销什么。

如果您的Web应用程序足以满足Hazelcast Web会话群集提供的内存会话群集,该怎么办?

如果我们使用servlet容器,这将没有问题,但我们不是(Netty是Webflux的默认设置),而Spring Session目前不提供ReactiveSessionRepository的Hazelcast实现。

但是所有这些都没有丢失,因为我们可以使用RezelMapSessionRepository传递Hazelcast的IMap。

使用Hazelcast进行内存会话群集

您可以在此处找到随附的GitHub存储库中的所有代码。

  • 配置Hazelcast
  • 创建一个Config bean,因为Spring Boot使用它来自动配置Hazelcast实例(有关更多详细信息,请参见此处)。
  • 由于我们自己创建Hazelcast映射,因此通过设置合理的生存时间值来配置它以驱逐过期的会话非常重要(默认值为0,这意味着会话将无限生存)。
  • 配置spring会话以使用Hazelcast映射
  • 确保添加@EnableSpringWebSession。
  • 创建一个ReactiveSessionRepository 包装Hazelcast实例映射的 bean。
  • 测试它是否有效
  • 查看GitHub存储库并转到build.gradle所在的根目录,并按照以下步骤操作:
  1. 打开终端窗口并运行命令: SERVER_PORT=1234 ./gradlew bootRun。
  2. 等待服务器启动,然后打开另一个终端窗口并运行命令:SERVER_PORT=6789 ./gradlew bootRun。
  3. 打开Web浏览器并转到URL:http:// localhost:1234
  4. 多次刷新页面,您应该看到会话ID以及点击计数递增。
  5. 在同一浏览器中打开另一个选项卡,然后转到URL:http:// localhost:6789
  6. 您应该看到会话ID相同并且命中计数已递增。
  7. 在住时间值设置为30秒,所以如果会话没有30秒,然后它会被驱逐访问。您可以在终端上的日志中看到此输出,并在您访问任何URL时创建新会话。


分享到:


相關文章: