MongoDB春季会议:竞争状况?

问题描述

我们在负载均衡器后面有一个应用程序,该应用程序仅支持轮询而不是粘性会话。

Spring Boot应用程序在OpenShift集群中运行,并且部署中有许多Pod。我们至少有两个吊舱,但根据负载的不同,最多可以扩展到10或20个。

该应用程序使用Spring Session和Spring Security。由于应用程序已经将MongoDB用于其他用途,因此将Spring Session配置为使用MongoDB(而非Redis)。

在低至中等负载功能测试期间,我们注意到会话属性“丢失”的问题:更新这些条目的代码成功运行,但是在请求完成后,该属性的较旧内容在会话中。这是随机发生的。

使用该应用程序的单个实例进行测试,没有发现此类现象。

对我来说,这闻起来像是在向Session对象写回Mongo之间的竞争状态,其中一个pod上有一些HTTP请求使另一个pod中的写回开始,而“错误的”获胜。

  • 这对于带有MongoDB的Spring Session是否有效?换句话说,这应该起作用吗?
  • 如果该方法可行,我如何找出正在发生的事情,以及如何解决该问题?
  • 如果不起作用,是否有Spring Session设置可以允许跨应用程序服务器共享会话状态而没有竞争条件?

解决方法

我们与数据库团队一起度过了很多时间,试图弄清这是否与MongoDB客户端连接或服务器配置有关,但经过更深入的研究之后,我发现了罪魁祸首:这是春季会议-data-mongodb,因为它无法实现增量更新。

https://github.com/spring-projects/spring-session-data-mongodb/issues/106

问题在于,没有逻辑可以检查是否有必要对会话存储库进行写操作,或者是否有任何跟踪可以更改会话的哪些属性的信息。该会话将无条件地写回每个请求的末尾。

如果您有多个并发请求,就像任何普通的Web应用程序一样,会话状态将从最后启动并首先完成的请求中保留下来。因此,简单的图像检索(通过Spring处理程序处理)将导致回写会话。如果您像我们一样拥有一个登录处理程序,该处理程序由于从后端系统检索了一堆用户信息而花费大量时间(最多2秒),那么在登录请求后便开始了对图像的请求,但会在此之前完成。然后spring-session-data-mongodb决定登录处理程序中的会话状态为陈旧,并且无法保存它。

因此,在修复该错误之前,我们将需要使用其他存储库,例如Redis。