Multi-tenant Architecture for SaaS
The central core of SaaS design is a multi-tenant architecture.
The central core of SaaS design is a multi-tenant architecture.
In this video, Mr. Derek Comartin outlines different ways to segregate a tenant’s compute and data storage in a multi-tenant architecture for SaaS applications.
Single & Multi Tenant
From 00:38, Derek starts by taking an example of a single tenant in a multi-tenant system. The app compute here is the actual application used by the tenant and storage is the database or cache system. For a single tenant, you would specify only a single node for compute and storage resources.
If we want to move to a multi-tenant environment from this single-tenant system, the first common way to do this is by replicating the same environment for another tenant. This will mean that we will have a separate compute instance and separate data storage.
This means that both tenants are completely siloed. In this model, you won’t have to worry about one tenant accessing another tenant’s resources. However, one of the tenants may be barely using your application, and you will still have the cost of that compute.
Pooled Compute & Siloed Data
From 02:15, he shows the next model of pooled compute and siloed data. In this model, you will let each tenant use the same application. However, depending on the tenant, your app will decide which database to go to. This way, you will be leveraging more of your app compute.
At 02:40, Derek shows another way of doing this, which is by partitioning the data. So, instead of having siloed data, we will have the same database for each tenant. Each tenant is given an ID. In this type of database, the data will be partitioned into a single database and will be stored regarding a tenant’s ID.
Pooled Compute & Partitioned Data
From 03:33, Derek starts to explain the concept of identity key for pooled and partitioned data. The identity helps us understand what partition a tenant belongs to.
For example, if we are using an identity API and the user logs in, we give it some type of key which contains some identity that can tell us what type of tenant is interacting with the application.
When the user makes a request to compute, he sends that key to it. We will then use this tenant ID as a partition key to access the relevant data. Also, if we are using the siloed database, we can still use this ID to direct the tenant to a specific database.
Code Example
From 05:00, Derek shows the code example in C Sharp of how we can manage this. In the code, he shows a ‘OderDbContext’ which takes a token. Inside the token, there is a tenant ID. This is passed to the constructor of ‘OrderDbContext’. There is also a query filter that filters the data model by that tenant ID in the token.
At 06:10, he creates a new grid for tenant one as the tenant ID and adds an order. The same thing is done for tenant 2 with a completely different grid. Then, when he fetches the orders for tenant 1, he gets it without using a filter on fetching.
At 06:35, he explains the same code for siloed data. However, instead of having a query filter, we will be pointing to the right connection string with an instance based on the tenant. All in all, the model remains the same and you need a user identity to make requests.
Hypermedia
From 07:14, Derek presents another option for multi-tenant architecture, which is by using hypermedia in two different ways. The first is with an HTTP API. In this model, when the tenant gets the identity, we will identify what hosts we will make our HTTP request to. We will direct the request and it will access the data storage in the lane.
At 08:18, he explains the multi-tenant farms’ concept where we have an MVC system. In this system, when a user logs in to our system, we will redirect him to the appropriate host for that tenant. The benefit of this approach is that these lanes allow us flexibility in terms of deployment. For example, if we make changes or an update, we can do it to app 1 and see the consequences. It will not affect all of our tenants.
Conclusion
At 09:29, Derek concludes the session by summarizing all the different ways to deal with a multi-tenant environment. We can silo data or partition it. Also, we can pool compute, and pool it by a set of tenants, or create different lanes. While writing code for our application, we can also do it by query filter or connect to a specific instance. However, all of this should be seamless while writing code for your application.