When my foray into Spring-Boot backed Microservices gave HTTP Session an existential crisis, I knew it was time that I should dabble with Spring Sessions.
You have multiple instances of a microservice behind a load balancer and you need the session to be maintained for the user after successful authorization, regardless of which instance is executing the request.
- Centralized Sessions — Maintain sessions in a common location for all instances to share.
- Consistent Hashing — Load balancer decides which instance to send the request to.
We will focus on Centralized Sessions here.
If the number of concurrent users of your application doesn’t run into a few hundred million then an In-memory data store is a good solution.
Redis is a fast In-memory solution for caching. We will cache the Spring Session object in Redis.
Architecture for Microservices
- Zuul Gateway
- UI Microservice
- Eureka Microservice
We will have multiple load balanced instances of UI Microservice, this means that a request from the user can be routed to any of the instances of the UI Service and that user can be routed to an instance where he has no session available.
And that’s problematic.
How does Centralized Sessions work in Spring?
A web server creates a HTTP Session for spring to work on and save authentication details and other user/request specific details. The server then send the Session ID back to the client in a cookie. 🍪
This works fine, if you have a single instance of an application. All hell breaks loose when microservices come into the picture. To mitigate this Spring came up with Spring Session.
Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution.
It replaces the HttpSession in an application container (i.e. Tomcat) in a neutral way, with support for providing session IDs in headers to work with RESTful APIs.
We need to save this session somewhere that is common to every instance. And that common place should be very fast to return back the details of the session.
So, we need a cache. But what kind? Database or In memory?
Both have their pros and cons. Database is cheaper on the storage but is slow. In-memory cache while fast will have to work with a limited amount of RAM.
If your concurrent users aren’t in the millions and you have decent enough servers then In-memory caching is the better solution here.
How does this work?
- We inform Spring that sessions will now be cached in Redis.
- Spring receives a request.
- Spring Security kicks in and user is authenticated.
- Spring Session object is serialized and saved in the cache.
- Client gets a cookie with the Session ID.
- Client then sends the session id for further requests.
- Any instance of the UI Service will check in the cache for a session object against the Session ID provided by the client.
- Session object is de-serialized and reused.
This annotation when parsed, creates a Spring Bean with the name of
springSessionRepositoryFilter that implements
Filter. The filter is in charge of replacing the
HttpSession implementation to be backed by Spring Session. In this instance, Spring Session is backed by Redis.
Now we need to tell spring where the redis cache can be found. Add the following in the bootstrap.properties or application.properties
When you try to login to the UI service, new keys are generated in the cache.
Use redis-cli and execute redis-cli KEYS *
These keys have their TTL and session expires when the keys are evicted from the cache.
We have successfully created centralized sessions for a microservice.