Stateful Vs Stateless Services

Introduction

From the intro to CS classes where we are programming "restaurant ordering software" and "tic tac toe games", we are taught that classes let you store state and behavior mutating that data in the same place. To me this always sounded like a sane way of doing things, everything has it's own state and communicate with it to change it's state. Shortly after, I was writing my first web service and was surprised to find out that my OrdersClass, which stored a list of a user's orders as an attribute, only ever held 1 single item in the array at any given request. I had just discovered that similar most major backend web frameworks Rails was stateless, and what I was looking for between requests persisting the mutated was called "stateful".


Stateful

This discovery led me into learning the difference between stateful and stateless services. The mental model behind stateful is pretty similar to how we are taught OOP. An object has a state, you mutate the state, and on the next call you get the new state that has been mutated, it remembers what you did to it, and does not reconstruct itself from scratch.

Think of a number summing service, it takes a number and returns the sum of all numbers ever sent to the service.

The interaction with this service would look something like this:

  1. The service is booted up and holds sum = 0.
  2. If you get the current sum on the service it will be 0.
  3. Request is made with number to add as 5, now the service will add to it's current sum (0) the number 5
  4. If you get the current sum on the service it will be 5.
  5. Another request is made to add number 7, now the service will add it's current sum (5) the number 7
  6. If you get the current sum on the service it will be 12.

Between each request it remembered what the previous request did to the object's state. Unless we restart the service it will persist it's last state even on the next request.


Stateless

The mental model for statelessness is that every time you interact with a stateless service you will be interacting with a clean slate every time, all the objects would be initialized just for you with their initial state as their stored state(mostly). Let's go back to the number summing service example, what would happen if this service was stateless?

  1. The service is booted up and holds sum = 0.
  2. If you get the current sum on the service it will be 0.
  3. Request is made with number to add as 5, now the service will add to it's current sum (0) the number 5
  4. If you get the current sum on the service it will be 0.
  5. Another request is made to add number 7, now the service will add it's current sum (0) the number 7
  6. If you get the current sum on the service it will be 0.

You get the idea, not very useful for data that needs to be persisted. So how would you create a stateless service that works correctly? We would take the data that needs to be persisted/stored/remembered and write in some sort of storage (a database, a file, a cache), just any external process that is not recreated on every request.

  1. The service is booted up and fetches it's last sum from storage. If the sum is not currently there in the storage we will let it be equal to 0.
  2. If you get the current sum on the service it will fetch it from the storage or if no sum has been stored before it will return 0.
  3. Request is made with number to add as 5, now the service will fetch the last stored sum from storage (0), add 5 to it and then rewrite it to storage (5).
  4. If you get the current sum on the service it will fetch the latest sum from external storage, 5.
  5. Another request is made to add number 7, now the service will fetch the last stored sum from storage(6), add 7 to it and then rewrite it to storage (12).
  6. If you get the current sum on the service it will fetch the latest sum from external storage, 12.


Real World Scenario

Now from the first glance stateful seems a lot more simpler, and almost all applications you use work like they are stateful (facebook wont make you signup everytime you want to go on it, you signup once and it will remember). Yet most web services written in production today are stateless.

Imagine if we have a lot of users and one server is just does not have enough throughput (requests/second) to handle the traffic without compromising latency. So we decide instead of running our number running service on a single server we will distribute our user traffic across 2 servers running an instance of the number summing service.


A stateful scenario

If our service is stateful, they will both hold a different sum, and if you add a number to server A, you will only get the right answer if you retrieve the state stored in number A, this means that scaling horizontally and distributing load evenly across multiple machines will now become harder, because every request has to go to the same server it went to previously. Imagine mapping every request to where it was first hit... in short you messed up should have been smarter and gone the stateless route.


A stateless scenario

Now imagine the same scenario with multiple servers running number summing service with traffic being routed/distributed evenly between those 2 servers. Since they are stateless and they store their state in an external database, each server uses the same source of truth, and does not care which server the request initially hit. This makes horizontally scaling a lot easier, and reduces the complexity of the load balancer trying to figure out which request goes to which server, you can just alternate between the 2 servers, or go round robin between multiple servers.

Comments

Commenter: Anon

Great post. This gives a good description of how to build a stateless service that still has some “state” to it like users expect.

Commenter: Hamdaan Khalid

Thank you!

Add a comment: