Content Developer II at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
122735 stories
·
29 followers

Multi-Tenancy: What is it and why do you care?

1 Share

I’m always on the lookout for ideas about how to endlessly promote both Marten & Wolverine. Since I’ve been fielding a lot of questions, issues, and client requests around multi-tenancy support in both tools the past couple weeks, now seems to be a good time for a new series exploring the existing foundation in both critter stack tools for handling quite a few basic to advanced multi-tenancy scenarios. But first, let’s start by just talking about what the phrase “multi-tenancy” even means for architecting software systems.

In the course of building systems, you’re frequently going to have a single system that needs to serve different sets of users or clients. Some examples I’ve run across have been systems that need to segregate data for different partner companies, different regions within the same company, or just flat out different users like online email services do today.

I don’t know the origin of the terminology, but we refer to those logical separations within the system data as “tenants.”

My youngest is very quickly outgrowing Dr. Seuss books, but we still read “Because a Bug went Kachoo!” above

It’s certainly going to be important many times to keep the data accessed through the system segregated so that nobody is able to access data that they should not. For example, I probably shouldn’t be able to read you email inbox when I lot into my gmail account. For another example from my early career, I worked with an early web application system that was used to gather pricing quotes from my very large manufacturing company’s suppliers for a range of parts. Due to a series of unfortunate design decisions (because a bug went kachoo!), that application did a very poor job being able to segregate data, and I figured out that some of our suppliers were able to see the quoted prices from their competitors and get unfair advantages.

So we can all agree that mixing up the data between users who shouldn’t see each other’s data is a bad thing, so what can we do about that? The most extreme solution is to just flat out deploy a completely different set of servers for each segregated group of users as shown below:

While there are some valid reasons once in awhile to do the completely separate deployments, that’s potentially a lot of overhead and extra hosting costs. At best, this is probably only viable for a finite number of deployments (Gmail is certainly not building out a separate web server for every one of us with a Gmail account for example).

When a single deployed system is able to serve different tenants, we call that “multi-tenancy.”

According to Wikipedia:

Software multitenancy is a software architecture in which a single instance of software runs on a server and serves multiple tenants.

With multi-tenancy, we’re ensuring that one single deployment of the logical service can handle requests for multiple tenants without allowing users from one tenant to inappropriately see data from other tenants.

Roughly speaking, I’m familiar with three different ways to achieve multi-tenancy.

The first approach is to use one database for all tenant data, but to use some sort of tenant id field that just denotes which tenant the data belongs to. This is what I termed “Conjoined Tenancy” in Marten. This approach is simpler in terms of the database deployment and database change management because after all, there’s only one of them! It is potentially more complex within your codebase because your persistence layer will always need to apply filters on the data being modified and accessed by the user and whichever tenant they are part of.

    There’s some inherent risk with this approach as developers aren’t perfectly omniscient, and there’s always a chance that we miss some scenarios and let data leak out inappropriately to the wrong users. I think this approach is much more viable when using persistence tooling that has strong support (like Marten!) for this type of “conjoined multi-tenancy” and mostly takes care of the tenancy filters for you.

    The second approach is to use a separate schema for each tenant within the same database. I’ve never used this approach myself, and I’m not aware of any tooling in my own .NET ecosystem that supports this approach out of the box. I think this would be a good approach if you were building something on top of a relational database from scratch with a custom data layer — but I think it would be a lot of extra overhead managing the database schema migrations.

    The third way to do multi-tenancy is to use a separate database for each tenant, but the single deployed system is smart enough to connect to the correct database throughout its persistence layer based on the current user (or through metadata on messages as we’ll see in a later entry on Wolverine multi-tenancy). This approach is shown below:

    There’s of course some challenges to this approach as well. First off, there’s more databases to worry about, and subsequently more overhead for database migrations and management. This approach does give you rock solid data segregation between tenants, and I’ve heard of strong business or regulatory requirements to take this approach even when the data volume wouldn’t require this. As my last statement hints at, we all know that the system database is very commonly the bottleneck for performance and scalability, so segregating different tenant data into separate databases may be a good way to improve the scalability of your system.

    It’s obviously going to be more difficult to do any kind of per-tenant data rollup or summary with the separate database approach, but some cloud providers have specialized infrastructure for per tenant database multi-tenancy.

    A Note about Scalability

    I was taught very early on that an effective way to scale systems was to design for any given server to be able to handle all the possible types of operations, then add more servers to the horizontal cluster. I think at the time this was in reaction to several systems we had where teams had tried to scale bigger systems by segregating all operations for one region to one set of servers, and a different set of servers for other regions. The end result was an explosion of deployed servers and frequently having servers absolutely pegged on CPU or memory while North America factories were in full swing while the servers tasked with handling factories on the Pacific Rim were completely dormant when their factories were closed. An architecture that can spread all the work across the cluster of running nodes might often be a much cheaper solution in the end than standing up many more nodes that can only service a subset of tenants.

    Then again, you might also want to prioritize some tenants over others, so take everything I just said with a grain of “it depends” salt.

    Thar be Dragons!

    In the next set of posts, I’ll get into first Marten, then Wolverine capabilities for multi-tenancy, but just know first that there’s a significant set of challenges ahead:

    • Managing multiple database schemas if using separate databases per tenant
    • Needing to use per-tenant filters if using the conjoined storage model for query segregation — and trust me as the author of a persistence tool, there’s plenty of edge case dragons here
    • Detecting the current tenant based on HTTP requests or messaging metadata
    • Communicating the tenant information when using asynchronous messaging
    • Querying across tenants
    • Dynamically spinning up new tenant databases at runtime — or tearing them down! — or even moving them at runtime?!?
    • Isolated data processing by tenant database
    • Multi-level tenancy!?! JasperFx helped a customer build this out with Marten
    • Transactional outbox support in a multi-tenanted work — which Wolverine can do today!

    The two “Critter Stack” tools help with most of these challenges today, and I’ll get around to some discussion about future work to help fill in the more advanced usages that some real users are busy running into right now.



    Read the whole story
    alvinashcraft
    1 hour ago
    reply
    West Grove, PA
    Share this story
    Delete

    .NET 9 LINQ Performance Edition

    1 Share

    .NET 9 LINQ Performance Edition
    6 minutes by Steven Giesel

    As with almost every edition of .NET, the team has been working on improving performance. In this blog post, we will see some improvements to the related tickets and benchmarks.

    Add secure authentication, MFA, social login, and more to your .NET app easily with FusionAuth
    sponsored by FusionAuth

    FusionAuth provides flexible authentication which works in any environment. In this quickstart guide, you’ll learn how to build an application with C# and .NET and integrate it with FusionAuth in five easy steps. The hyper-versatile auth platform works seamlessly for server applications, SPAs, mobile apps, back-end services, and anywhere else you could ever need authentication.

    Serialising ASP.NET method calls for later execution
    6 minutes by John Reilly

    How can we take a method call, serialise it, perhaps store it in a database, and then later rehydrate and execute?

    Writing “string.IsNullOrEmpty” using pattern matching and comparing the resulting code
    4 minutes by Jiří Činčura

    No matter whether you prefer string.IsNullOrEmpty(s) or s is null or { Length: 0 } or s is null or [] (or some other decent form of expressing this), the resulting instructions that CPU needs to process, will be the same.

    Where are my traces?
    6 minutes by João Antunes

    A post about a weird gotcha João found when using distributed tracing with OpenTelemetry .NET, in a system where not all services have otel setup

    Fast Search and Replace in Large Number of Files: A Practical Guide
    about 1 hour by Brian C. Hart

    Efficient file processing techniques, including memory-mapped files for high-speed I/O and asynchronous programming for parallelism, are covered. Implementing a user-friendly interface with a modal progress dialog that displays real-time progress and file paths while preventing interaction with the main application is also presented.

    newsletters


    Would you like to become a sponsor and advertise in one of the issues? Check out our media kit and get in touch.

    Read the whole story
    alvinashcraft
    4 hours ago
    reply
    West Grove, PA
    Share this story
    Delete

    F# Weekly #20, 2024 – 30th anniversary of the invention of the |> operator

    1 Share

    Welcome to F# Weekly,

    A roundup of F# content from this past week:

    News

    Videos

    Blogs

    F# vNext

    Highlighted projects

    New Releases

    That’s all for now. Have a great week.

    If you want to help keep F# Weekly going, click here to jazz me with Coffee!

    Buy Me A Coffee

     





    Read the whole story
    alvinashcraft
    4 hours ago
    reply
    West Grove, PA
    Share this story
    Delete

    The Career Three-Body Problem

    1 Share
    The (career) three-body problem is an impossible to solve puzzle where we try to find balance between competing objectives in our professional lives.
    Read the whole story
    alvinashcraft
    5 hours ago
    reply
    West Grove, PA
    Share this story
    Delete

    View-Based Authorization in ASP.NET Core

    1 Share

    View-based authorization is an authorization strategy that enables us to manage UI elements’ visibility based on the user’s identity. In this article, we’ll take a look at how we can achieve view-based authorization in an ASP.NET core application. Let’s begin. What Is Authorization? Before we dive deeper into the implementation of view-based authorization, let’s take […]

    The post View-Based Authorization in ASP.NET Core appeared first on Code Maze.

    Read the whole story
    alvinashcraft
    5 hours ago
    reply
    West Grove, PA
    Share this story
    Delete

    From Visual Basic to Visual Studio: A Journey Through Microsoft’s IDE Evolution

    1 Share
    The author shares their journey from Visual Basic 2 in 1992 to the latest tools like Visual Studio and Visual Studio Code (VS Code). They emphasize the evolution of Microsoft's IDEs for software, web, and database development. They advocate for a hybrid approach of using IDEs for efficiency and familiarizing with CLI commands for flexibility.





















    Read the whole story
    alvinashcraft
    5 hours ago
    reply
    West Grove, PA
    Share this story
    Delete
    Next Page of Stories