2
votes

We have an application behind a load balancer that only supports round-robin, no sticky sessions.

The Spring Boot application runs in an OpenShift cluster, with a number of pods in a deployment. We have at least two pods, but might scale this up to 10 or 20, depending on load.

The application uses Spring Session and Spring Security. Spring Session is configured to use MongoDB (not Redis), since the application is already using MongoDB for other purposes.

During functional testing with low to moderate load, we have noticed issues with session attributes "going missing": the code that updates these entries runs successfully, but after the request is finished, the older contents of the attributes is in the session. This happens randomly.

Testing with a single instance of the application, no such observations were made.

To me, this smells like a race condition between the write back of the session object to Mongo, with some HTTP request on one pod racing the write back in another pod, and the "wrong one" winning.

  • Is this a valid usage scenario for Spring Session with MongoDB? In other words, is this supposed to work?
  • If it is supposed to work, how can I find out what's happening, and what can I do to solve the issue?
  • If it's not supposed to work, is there a Spring Session setup that would allow a cross application server sharing of session state without race conditions?
1
Any chance this would have to do with read/write quorums? some latency in replication? What's that MongoDB we're talking about? MongoDB should do fine hosting sessions, though replset or clusters might not be the best use case for this - then, redis is indeed a good fit, could easily be deployed in OpenShift - SYN

1 Answers

2
votes

We spent a lot of time with the DB team trying to figure out if this had anything to do with the MongoDB client connection or server configuration, but after some more thorough research, I've found the culprit: it's spring-session-data-mongodb, because it fails to implement delta updates.

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

The problem is that there is no logic to check if a write to the session repository is necessary, or any tracking which attributes of the session have been changed. The session is written back at the end of every request unconditionally.

If you have multiple concurrent requests, like any normal web application has, the session state survives from the request that was started last and finished first. So a simple image retrieval (that is handled through a Spring handler) will cause the session to be written back. If you have, like we do, a login handler that takes a substantial amount of time (up to 2 seconds) because it retrieves a bunch of user info from a backend system, the request for the image will have started after the login request, but will have finished before it. spring-session-data-mongodb then decides that the session state from the login handler is stale, and fails to save it.

So until that bug is fixed, we will need to use a different repository like Redis.