Session Replication is a recurrent topic when talking about high availability. As mentioned in a previous article by Leif Åstrand, Session Replication in the World of Vaadin, the recommendation is to rely on session replication as little as possible. This is due to the efforts required to make the Vaadin application state stored in the HTTP session, to be fully serializable and distributable on different servers on the network.
However, for applications that need session replication, we at Vaadin put efforts into backing a solution to help developers reach the goal.
Meet the Kubernetes Kit
To make it easy for developers to build scalable, highly available, and user-friendly Vaadin applications ready to be deployed on cloud providers supporting Kubernetes, we built the Kubernetes Kit.
The main features provided by the kit are:
- Non-disruptive rolling updates that don’t interrupt user sessions.
- Horizontal scalability by allowing applications to scale up and down without impacting active user sessions.
- High availability, enabling users to keep their active sessions and continue using your application even if a server fails.
- Serialization helpers that make it faster and easier to leverage fully horizontal scaling and fail-over.
How does the Kubernetes Kit work?
The Kubernetes Kit provides session replication functionality by asynchronously serializing the HTTP session attributes in binary format at every request that may change the UI state, and storing the data in a pluggable distributed storage.
The serialized session is assigned a unique identifier, tracked by a browser cookie. If the server instance crashes or is dismissed, the new server will be able to restore the session by requesting the data associated with the identifier stored in the cookie.
Differently from other replication solutions that deserialize and serialize sessions for every single request, the Kubernetes Kit restores the data from the distributed storage only when a new HTTP session is created, whereas it always serializes and saves data remotely.
This is the best way to make the Vaadin application work seamlessly and to prevent performance degradation on the side of user experience.
In a clustered environment, the assumption is that the Sticky Sessions strategy is in use so that the user will always be routed to the same server until it is unavailable.
From an architectural point of view, the building blocks of the Kit are:
The Session Serializer is the component that serializes and deserializes HTTP session attributes, producing a binary stream that will be saved on the distributed storage. It takes care of serializing the most recent version of the UI by respecting Vaadin Session locks, which prevents concurrent changes to the same UI.
The Session Tracking Filter: a Java Servlet Filter responsible for serializing the HTTP session after every request that changes the UI has been processed. It also deals with handling the cookie used to track the identifier of the serialized session.
The Session Listener: a listener for HTTP session creation and destruction. On session creation, it fetches serialized data from distributed storage and fills the HTTP session with the deserialized attributes. Upon destruction, it deletes the serialized data associated with the current HTTP session from the distributed storage.
Transient field handling for Spring-based projects: The Kubernetes Kit inspects objects being serialized for transient fields to determine if they hold references to Spring-managed beans. If this is the case, additional metadata is stored along with the session attributes. During deserialization, the information is processed, and the transient fields are injected with the compatible bean instance present on the new server. This is especially important for UI components that reference singleton service or scoped beans since the cardinality of these objects must be preserved.
The architecture works as described in the following diagram;
- The Vaadin application is loaded in the user's browser, and interaction with it begins. Interactions result in the transmission of HTTP requests to the server.
- The HTTP request is intercepted by a filter. If an HTTP session does not already exist, the filter requests one.
- On the HTTP request, a tracking cookie with the identification of the session entry in the distributed storage may be present. If yes, distributed storage is accessed to get serialized session data.
- Serialized data is read from the storage and returned to the HTTP session listener.
- That, in turn, asks the Session Serializer component to deserialize data into the newly created HTTP session.
- The HTTP session is then ready to be used.
- The HTTP request continues to be processed by registered filters and servlet.
- If the HTTP request may have produced changes in the Vaadin UI, a session serialization request is enqueued.
- The response to the HTTP request is sent back to the browser.
- The HTTP session is serialized asynchronously. The Session Serializer first tries to serialize the session when the Vaadin Session is unlocked (optimistic serialization); if, after several attempts, it is not possible to complete the serialization, it falls back to a pessimistic approach, explicitly locking the Vaadin Session until the serialization is completed.
- Once the session is serialized, the binary data and distributed session identification are transmitted to the distributed storage to be persisted.
The Kubernetes Kit Session Replication Debug Tool
In addition to the product features, the Kubernetes Kit provides a debug tool to be used in development mode, whose purpose is to help make HTTP sessions fully serializable and deserializable, by discovering the main issues during development.
The tool uses an HTTP filter for each UI interaction to conduct serialization and deserialization of the HTTP session.
You can quickly determine if the UI state is serializable or not by navigating the application and looking at the server log. A notification will also show up on the browser if serialization fails if the Vaadin PUSH feature is enabled.
Data serialized by the debug tool is not persisted, and it does not affect the usage of the application.
The outcomes of the serialization and deserialization processes printed on the server log provide information such as;
- Process outcomes (for example, SERIALIZATION_FAILED, DESERIALIZATION_FAILED, SUCCESS, …)
- List of unserializable classes
- Object graph stack for both serialization and deserialization
- List of potential causes of SerializedLambda ClassCastException
By analyzing the information on the log, it should be easier to detect serialization issues. Similar information may also be obtained by setting the
sun.io.serialization.extendedDebugInfo system property.
Still, the debug tool has some advantages over this approach:
- With the debug tool, the serialization does not stop at the first unserializable class. The offending object is nullified and the serialization process can continue so that multiple errors can be discovered with a single run.
extendedDebugInfois enabled, the
toStringmethod is called on objects to represent them on the serialization stack. If the method fails for any reason, the process will stop. The debug tool can detect such a situation and, if needed, replaces the failing object with a proxy instance capable of serializing and deserializing its fields.
extendedDebugInfoproperty has effects only on serialization. The debug tool also provides this capability during deserialization.
The debug tool is active only in development and only if the following preconditions are met:
vaadin.devmode.sessionSerialization.enabledconfiguration property is set to
sun.io.serialization.extendedDebugInfosystem property is set to
- JVM is started with
extendedDebugInfo property and the
--add-opens instruction are required to provide as much detailed information as possible.
For Spring Boot projects, it is automatically installed if the above conditions match. The installation must be applied manually for other setups, as explained in the documentation.
Session replication for high availability is not easy to do because many problems need to be solved first. The Kubernetes Kit makes it easy to create fully serializable and distributable Vaadin applications and deploy them on any Kubernetes-ready cloud provider.