Origins of State Management
State information is required to do just about anything meaningful with software programs because data about an activity is fundamental to runtime processing.
Older, two-tier client-server solutions made state management a natural part of the primary solution components. The client user-interface would often retain large amounts of activity-specific data in memory for extended periods (Figure 1). This was not considered a problem because each client program was deployed on a dedicated computer, intended for use by a single user.
Figure 1 - Typical one-sided division of state management responsibilities in a typical two-tier client-server architecture.
In traditional distributed computing models, application processing logic shifted from the client workstation to the middle tier. As a result, a server-side program was now required to manage interaction with multiple client programs, each with their own individual state information processing requirements (Figure 2).
Figure 2 - Note that the "y/2" value is arbitrary. In most contemporary Web-based solutions the clients are relatively thin (browser-based), requiring the server-side components to manage a higher percentage of state data.
When actively processing or retaining state information, a program is constantly consuming a base amount of memory and CPU cycles. A server-side program accessed concurrently by multiple clients can rapidly and significantly increase this amount (Figure 3).
Because runtime usage scenarios are not always predictable and because hardware budgets are not always flexible, the risk of a concurrently accessed server-side program becoming a performance bottleneck is very real. Although state data processing requirements are not always the primary cause of system memory consumption, they contribute significantly.
Figure 3 - Multiple clients concurrently accessing the same application component. Some enterprise solutions have thousands of clients that can raise concurrent access numbers into the hundreds.
In response to this problem, variations of distributed architectures were formed to alleviate components from state management responsibilities by providing state delegation and state deferral options. A common architectural extension that supported state deferral was centered around alternative state storage. A dedicated database (or a set of dedicated tables within an existing database) could be used by components to write and then later retrieve state data (Figure 4).
Often these databases were physically located on the same application server as the components (as opposed to a separate database server) to reduce the performance impact caused by remote data access. In-memory databases were also used to further optimize data access by avoiding disk access.
Figure 4 - A separate database positioned as a state management deferral extension of the architecture (the orange area represents state data). Note that databases utilized in this role are often located on the application server alongside components.
To-date, a variety of state management approaches have been developed. Middleware, for example, has become a popular state processing deferral option. It establishes a central, self-sufficient, and intentionally stateful part of the infrastructure that can be leveraged by other solutions within the enterprise. The deferral of state data to the messaging layer is another viable option, and one that is a focal point of REST-style architecture.