Today we’re excited to announce public beta support for HTTP session affinity, a feature that makes building real-time applications easier than ever. Session affinity improves end user experience in certain types of applications and architectures where you require some level of extra state within your application code, because it ensures related requests get routed to the same instance of your code. This improves performance reducing the need to go and get the needed state for a specific user.
At high level, here's how it works: When you enable session affinity on your application, the Heroku router will set a special cookie on every HTTP request. This cookie will allow our routing layer to consistently route requests for a client session to the same dyno. This means you can reduce the roundtrip needed to get various session data for a user making your real-time applications fast and responsive.
$ heroku labs:enable http-session-affinity
We’re extremely excited to introduce this, having already received some great reactions, such as the following from Guillermo Rauch, creator of Socket.io:
"Heroku always executes with the right developer experience. Just a flag for enabling session affinity? They really get it."
We encourage you to give it a try today with some of our guides to help you get your hands dirty, or read on further for some of the background on how this works.
When building a web application the simplest way to ensure scalability is to have your web application be as stateless as possible. The key here is have all state or as much as possible in your backing services (such as a Postgres, Memcached, etc). This creates a certain level of chattiness as apps begin to embrace real-time features. In many cases, you can reduce this chattiness by keeping more information locally where possible.
Session affinity falls right in the middle of full sticky sessions and entirely stateless web front-ends. With session affinity, if a known dyno holds your session then you’ll be routed to it. If there isn’t one (this could be due to a dyno restart, a redeploy of your application, or your dyno having been scaled down) then we’ll route to a new dyno in which your application will grab the state from the database or other backing service. In this case, a new session will be established and used for future routing.
By default, when the router receives a request, it randomly selects a dyno to forward it to and then proxies the content to it. Every request is entirely standalone.
When session affinity is turned on, the router will assign a request randomly the first time it sees a particular client. When the response from the dyno passes through the router, it will add a header to the response asking the user to store a cookie named
heroku-session-affinity. The router then uses this cookie to identify the correct dyno to route future requests to.
Whether it’s due to a fresh code release, a server failure, or a crash in your code, sometimes that dyno will become unavailable. In such circumstances, the router will pick a new random dyno for this session, and subsequent requests will keep going there until the original dyno is back in place again.
When your application scales up, new dynos should receive an even share of traffic and relieve pressure on existing dynos. The router probabilistically plucks a portion of clients from their assigned dyno and reassigns them to the new one, ensuring roughly equal distribution.
Heroku’s session affinity mechanism ends up having the following properties:
- The effect of a dyno joining or leaving the entire set of dynos for an app is minimized.
- A dyno being unresponsive causes no downtime to the client; the request is routed to a different dyno temporarily
- The mechanism is portable and requires no modifications to the application no matter the platform or language, as long as the HTTP client’s users support HTTP cookies.
Session affinity meets a great middle ground. You account for failure cases by ensuring you’re not 100% sticky – thus leaving your application more fault tolerant. At the same time, apps that need this type of stateful behavior can now do so with far less code. If you’re using Meteor, Socket.io, Lift or another other library or framework that would benefit give it a try today.