As I mentioned in a previous post, I was responsible for architecting a clustered version of Sun's app server using HADB, a highly available, highly scalable database. Why did their clustered version need a scalable database? For one specific reason: session state.
One of the things that really sucked with the previous version of the app server was that their session state replication mechanism was completely broken. It would corrupt data or get into deadlocks, and couldn't scale beyond three or four nodes.
This was my first exposure to the demands of session state and how it impacts the back-end architecture. HADB is attractive because it, basically, never goes down, and it is transactional, so it would solve the reliability and scalability problems of the previous implementation.
The more I learned about session state, the more I disliked it. The impact to a system trying to be scalable and available was enormous.
First of all, load balancers have to be able to detect the session id and make sure that a request for an existing session was routed back to the same instance. Only certain hardware load balancers know how to do this, and it requires digging into the HTTP message to pull out a special cookie that tells you what instance owns the session.
Secondly, application servers have to be able to handle all this session state without using up all the memory of the system. So EJB invented this marvelously ugly word, "passivation", by which session state is written out to disk and dropped out of memory - in other words, a virtual memory system for session state.
And then there is the impact on the complexity and scalability of clustered systems. Because you never know when a given instance may go down, session state has to be relocatable to any other instance in the cluster. Trying to build something that does this correctly is complex, painful, error-prone, and, to be honest, annoying.
For the end users, you end up with systems that are always limited in some way or another. If you store session state in a shared database, this impacts response time, and this database is another moving part you have to administer. And it had better be highly available and scalable otherwise it can only handle so many instances -- ultimately the database itself impacts scalability.
If you use in-memory replication, then either you have to make the state available to all instances, which means lots and lots of data flying around the network, constraining scalability, or you have to pair up instances. This is dangerous, because if one instance goes down, the other instance has to handle
all the workload of the existing sessions of the downed instance -- you end up with hot spots and if you're not careful, a wonderful cascading failure scenario.
There is a giant sucking sound of processing power, time, money, and intellectual resources being used up on this problem, all because someone wants to store a shopping cart in HttpSession.
All of which leads me to conclude:
session state is evil.
When I read about the principles of REST, I was really taken by it. One principle that really stood out for me was:
stateless. HTTP was never meant to be stateful, and for good reason. Imposing state on this protocol is a bastardization of its original intent.
Rather than share my potentially confused view of this, I'll quote
Roy Fielding[1] directly from his
slides on REST that he gave at RailsConf:
- A successful response indicates (or contains) a current representation of the state of the identified resource; the resource remains hidden behind the server interface.
- Some representations contain links to potential next application states, including direction on how to transition to those states when a transition is selected.
- Each steady-state (Web page) embodies the current application state -- simple, visible, scalable, reliable, reusable, and cacheable network-based applications
- All application state (not resource state) is kept on client
- All shared state (not session state) is kept on origin server
Do you get it? I repeat:
all application state is kept on the client.
So stop asking the server to "hold on to things" for you. Please. If you do that one simple thing when you build an application architecture, you have freed the server infrastructure; you have given it wings.
Today it is easier than ever before to do this. With AJAX and RIA toolkits like
JavaFX (shameless plug), you can provide dynamic interaction with the user without having to ping the server all the time and have it store conversational state. You can even use
Java DB or
Google Gears to keep your client-side state persistent.
Because of these new web client technologies and patterns, I don't believe the concerns that saving state on the client necessarily results in more network traffic. You change your interaction with your server from lots of little requests with little bits of data to much less frequent requests with more data. In general, because of the overhead of a network request, I believe this is a Good Thing.
So, I know it's tempting to use session state. I know it seems easy at first. I know that all the server products out there give you utilities to do it and talk it up (they're even talking about letting you keep even more state around). But
Just Say No.
Don't Do It.
I have seen where it takes you, and it ain't pretty.
[1] I have a funny story about the first time I met Roy Fielding. I was at the Derby booth at ApacheCon, and Roy had come over to learn more about it. I didn't know him from Adam, and I asked him why he was interested. He said he was starting a new project in Apache to do document management.
I said with a big smile "welcome to Apache!". He looked at me for a second and said, "well, actually, I've been around Apache for many years..."
It was only later that I discovered that he was one of the founders and is currently a VP at Apache :)