ASP.NET sessions on Google Cloud Platform

Tim Sneath wrote a great post about storing session state with ASP.NET. This story attempts to build on that knowledge and evaluates the options on Google Cloud Platform. I measure the performance and cost of each option, and I provide sample code that can be used to evaluate other options not considered in this post.

The Inproc session state provider.

By default, a new ASP.NET application will use the Inproc session state provider. The Inproc session state provider stores session state in the Internet Information Server (IIS) process running the application. The Inproc session state provider is the fastest and inexpensive, but may lead to user frustration when machines are upgraded or removed from the webserver farm.

When the Inproc session state provider leads to frustrated users.

Let’s say you’re running your ASP.NET application on Google Compute Engine. Users love your application, and traffic is growing fast. Now, you have so much traffic that you need multiple webservers to serve it all. So, you create an HTTP load balancer and scale horizontally.

The load balancer adds a session cookie so that requests from the same web browser always arrive at the same IIS. This works fine for many applications. But beware: regardless of the type of affinity chosen, a web browser can lose affinity with its IIS.

Self-emptying shopping cart makes users unhappy.

In the worst case scenario, a user is shopping on your site and spends 20 minutes loading up their shopping cart. All their HTTP requests are served by the same IIS. The user clicks the Check Out button, and at the same time, the IIS they have been talking to goes offline, maybe for a Windows update. Oh no! All their shopping cart data was stored in that one IIS. When the user’s request arrives at a new IIS, their shopping cart is now empty! The user is likely to abandon your site in frustration, and for good reason.

Storing session data outside IIS.

To avoid frustrating users, the session data must be stored outside IIS, so that as web servers are brought up and down, users’ session data is preserved.

I wrote a simple ASP.NET application. It displays a form that allows the user to set session variables.

I also wrote a simple HTTP client to evaluate the solutions, including two solutions that were not discussed by Tim. The two new solutions are Redis and Google Cloud Datastore. Then, I ran all code in Google Cloud Platform’s us-central-1f zone. The results follow:

Inproc

  • Speed: The fastest, sub-millisecond.
  • Scales: Horizontally with session affinity and caveats discussed above.
  • Price: free. No charge beyond IIS GCE instance.
  • Lose data on reboot: Yes.

StateServer

  • Speed: Fast, a millisecond or two.
  • Scales: No. All your sessions need to fit in one state server.
  • Price: Estimated $18.69 per month for an f1-micro instance.
  • Lose data on reboot: Yes.

SqlServer

  • Speed: Fast, usually less than 10 milliseconds.
  • Scales: Horizontally as SQLServer.
  • Price: Estimated $86.87 per month for an n1-standard-1 instance.
  • Lose data on reboot: No.

Redis

  • Speed: Medium, around 90 milliseconds.
  • Scales: Horizontally as Redis cluster.
  • Price: Estimated $4.09 per month for an f1-micro instance.
  • Lose data on reboot: No.

Datastore

  • Speed: Slow, 300 to 400 milliseconds.
  • Scales: Infinitely with no supervision required.
  • Price: Free below about 8000 page loads per day, and about $0.54 for every 100,000 page views after that.
  • Lose data on reboot: No.

I implemented a session state provider that stores sessions in Google Cloud Datastore. It was surprisingly challenging, because the SessionStateStoreProviderBase class is a lot more complicated than a simple ReadSession() and WriteSession() interface I was expecting. Instead, the interface has methods like LockAndReadSession() and WriteAndUnlockSession(). Google Cloud Datastore has no intrinsic locking functions, so I had to implement locks with counters. This means the functions were implemented like this:

LockAndReadSession()
Begin transaction.
Read two entities.
Write one entity.
Commit transaction.
WriteAndUnlockSession()
Begin transaction.
Read one entity.
Write one entity.
Commit transaction.

Unfortunately, the many separate operations yield a comparatively slower running time. When the daily free quota has expired, the cost of using datastore will be:

3 reads + 2 writes = 3 * $0.06 + 2 * $0.18 = $0.54 per 100,000 page views, not including the cost of the storage. Session data is usually small.

Conclusions

There is no one best solution. The best choice for your application will depend on what is most important for your application: speed, price, minimizing user frustration, or minimizing the maintenance burden. Start ups will like Inproc and Redis for its affordability. Large applications with millions of users will like SqlServer for its combination of speed and reliability. If your web pages already take 2 or more seconds to load, then users will probably not notice the latency of sessions stored in datastore, and you’ll never need to worry about scaling or maintenance.

Disclaimer:

These performance benchmarks were measured and prices were calculated on January 9, 2017. They are not guarantees. When choosing a session state solution, you should evaluate performance and pricing for your particular application.

Like what you read? Give Jeffrey Rennie a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.