4
votes

Let's suppose I want to create a multi tenancy SaaS app using ASP.NET Core and I want to use Azure SQL elastic pool similar to this example: Microsoft Docs

The maximum number of databases per pool is 500: Azure Pricing

Additional information:

  1. I will start with Azure SQL single database

  2. I will be using Entity Framework Core

Questions:

  1. What happens if my app exceeds 500 users? What are the options to scale this efficiently? (when you reach the limit of the Elastic Pool)

  2. How well would the option fit with EF Core migrations?

  3. Any other suggestions on how to start and approach this later on?

1
Do you have a hard requirement on having separate db for each tenant? I mean, that will probably get quite expensive..jpgrassi
I'm still checking the other possibilities but I was wondering how this approach for db/tenant would work in Azure Elastic PoolChris

1 Answers

4
votes

Answer context

Before answering your specific questions, let me add some context about the solution I see. With multi-tenancy comes tenant management. And, just like in the document you've linked to, there's probably going to be some sort of catalog holding all tenant-specific information. One of these pieces of information could (most probably will) be a connection string to the tenant-specific database.

Imagine a tenant connects and the system gets the database to connect to from the catalog, based on which tenant it is (let's call it the context of the tenant). The application will hand the connection string over to the rest of the application to work with.

Now here's the beauty of the solution: that connection string can point (virtually) anywhere. It could point towards a database in a pool, or it could point to a managed instance. It could even point to an on-premises database that has been made available over the internet. All because the application is agnostic of where the data is, it just gets a connection string and goes to work.

1. What happens if my app exceeds 500 users? What are the options to scale this efficiently? (when you reach the limit of the Elastic Pool)

Assuming that by users you mean tenants: nothing happens. New databases are created in any location that's accessible to the application, for instance in a new pool. And since the connection string for a tenant can point anywhere, that's totally fine.

2. How well would the option fit with EF Core migrations?

The option fits as well with EF Core migrations as it does with any other database model: updates to the database need to be performed in a decent and managed way. This can for instance be done by running a migration or running an update script. Fact of the matter stays: you need to update multiple databases. And for that to work, it's smart to have a decent migration plan in place.

There are several options to mitigate possible issues, or at least limit the possibility of stuff breaking. One would be to only create migrations that only add to your current model. Another would be to decouple the database model from the application by having an asynchronous communication layer in between like a service bus.

This is quite a complex strategy to define and is highly dependent on factors like the type of application you're building, the frequency with which you'll have database updates and the complexity of your database scheme.

3. Any other suggestions on how to start and approach this later on?

As far as I'm concerned: if you know this is coming, act on it now. Implementing multi-tenancy is easiest early on. The further down the road, the harder it is because you probably start hard coding (not really, but sort of) connections in your application that need to be decoupled as soon as you want to add multi-tenancy.

Conclusion

If I interpreted your question correctly, you know multi-tenancy is going to be a 'thing' for your application. This means you need to address it from the start. But you don't have to have complete full-fledged multi-tenancy from the start... you just need to prepare for it.

Getting a bit more technical: you could for instance implement a TenantContext that identifies the tenant on login and gets the accompanying connection strings (storage, service bus, database, etc) on login. Then, in the rest of the application, get the connection strings from the TenantContext and use those to get tenant-specific data.

At first, for instance during development, the context can be really simple and only return the information for one tenant. But because of the decoupling you introduced, the rest of the application is already prepared for multi-tenancy. As soon as the need for it gets real, all you need to do is implement the TenantContext.

EDIT:
As an addition because of the comment below: there is a way to register DbContext instances in the DI system beforehand. You can implement something like a ConnectionStringResolver which is injected into the context. As soon as you actually need a DbContext, the tenant context is also known. The DbContext is constructed, using the ConnectionStringResolver to find the right connection string for the tenant.