In our first article, we took a look at the use of Single Page Applications (SPAs) for developers. This gives us a sense of where we can leverage new ways to build web-based application environments, and begin to rethink the architecture now that new ways are available to tackle some common application architecture issues.
Managing User State on the Server
Several times I have alluded to the fact that traditional request/response web applications manage user state on the server and a benefit to SPAs is that they manage user state in the SPA client itself. But the question I failed to answer is: why is this a good thing?
Let’s consider how state is managed by a traditional web container: the user logs into an application by providing user credentials (username and password), the web container creates a session for the user, and the web container returns an identifier back to the web browser with a session identifier, typically in the form of a cookie. Every time the web application makes a request to the server it sends the cookie so that the server can find the user’s session and perform actions on his behalf. It is a very simple model, but it works very well.
Now, what happens if that web container crashes?
If it is maintaining the guest’s session information in its memory then that session information is lost. This means that when the user makes a subsequent request to another web container in the environment, that web container will not have the user’s information and will require the user to re-login. How is this from a user experience perspective? Furthermore, how do virtual environments and containers that elastically come and go at will exacerbate this problem? Would you like to be connected to your favorite e-tailer and have to re-login every few minutes because the site is cycling virtual machines?
State, sessions, and knowing who is who
Obviously, storing a user’s session only on a single server is a bad idea, so what is the solution? In traditional web applications we would create a “cluster” of servers that all hosted the same application. The user would connect to a server, the load balancer would make the user’s session “sticky” so that he will always be directed to that server, and then replicate the user’s session information to a secondary server in case the primary server goes offline. When the primary server does go down then the load balancer has rules to redirect the user to the secondary server and the user gracefully “fails over” to the secondary server.
The implication, however, is that every time the session is updated, the session must be serialized and sent to the secondary server. If you want a higher degree of resiliency then you may opt for more than one secondary server, but that adds more overhead to the environment. This traditional fail over strategy is plagued with performance problems so many smart and creative minds devised other strategies, from storing sessions in a database to storing sessions in an in-memory store like Memcached or CouchBase to changing the sessions management problem altogether by using something like the Terracotta Server Array. Each of these solutions add complexity to the environment and really serve to solve a problem that could be (mostly) eliminated.
Simplifying the Solution
Let’s think about how we manage user state in a thick client application or in a mobile application. In this variety of applications, the user provides credentials, authenticates with the server, receives an authentication token (such as an OAuth token), and then passes the authentication token on subsequent server requests.
This sounds similar to our session management strategy, but the difference is that instead of storing the user’s state on the server, the client maintains the state and the server provides services at a granularity that the client can consume. For example, instead of maintaining a database cursor on the server in the user’s session to allow him to navigate through search results, the server instead provides services that allow the user to request a single page of search results, specifying the page size and the page number.
By breaking our server application into a set of services, or micro-services, as the industry has coined them, we are able to (mostly) eliminate server-based sessions and avoid the complexity presented above. Our services are clearly and cleanly defined and we rely on an authentication service to validate our users and an API management solution to authorize the user’s requests. Because our services are now stateless, we can scale them up and down as needed to meet user demand, without the complexity of sticky sessions and fail over.
SPAs change the session management paradigm entirely because the client application knows about the user and what he is doing. We’re still going to need services to manage stateful things like shopping carts, but SPAs solve the client-side issue of how we build elastic applications.
Single Page Applications (SPAs) more closely resemble thick client applications and provide a better experience for the user by moving much of a web application’s logic to the client. Web “pages” appear to load faster and the whole user experience is more fluid than with traditional request/response based applications. In addition, servers that support SPAs are more clearly defined and scale better than their request/response counterparts. But all of this requires a shift in the development and deployment mindset and will change the behavior of the servers you are tasked with managing.
This first article provided an overview of SPAs and presented some of the core features of SPA clients and SPA servers. Subsequent articles will review some specific SPA frameworks and look at how those applications affect the servers with which they interact.
Image source: Adventure Time (BMO) http://i.imgur.com/lSjkmNj.gif