Multi-tenant Architecture for SaaS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody it's derek martin from codopinion.com software as a service often means using a multi-tenant architecture there are many different ways that you can isolate a tenant's compute and data storage i'll show a few different options and why identity can play a significant role this video is brought to you by event store db the stream database built from the ground up for event sourcing cqrs and event driven micro services for more info on event store db check out the link in the description if you're new to my channel i post videos on software architecture and design so if you're into those topics make sure to subscribe at any point you find this video helpful please give it a thumbs up and leave a comment so first let's talk about a single tenant now this may be an individual user if we're just talking about consumers or if it's more of a business an organization a multi-uh user environment it's still a single tenant and then the app compute i'm talking about the actual application you're running application and storage this could be your database could be other things like a cache and throughout this video when i show compute there that doesn't necessarily mean you have a single node for your compute this could be a load balanced environment regardless we're talking about the compute resources that are specific for a tenant so if you've built kind of a single tenant environment and you need to move to a multi-tenant environment the kind of commonplace scenario that you would go to is just replicating that entire environment for another tenant meaning that you'll have a whole separate uh compute instances separate data storage so meaning that both tenants are completely siloed now this has some advantages of that they're just completely siloed environments and then you don't necessarily worry about one tenant accessing another test database or using the resources the compute resources of another tenant but exactly on the opposite flip side the trade-off here is that you may be using uh very little compute resources for a tenant if they're not using the application very much uh so tenant one here may be leveraging eighty percent of their compute and tenant two may be barely using your application and you still have that cost of that compute um whether you're in a cloud environment or not it's still cost so you're basically kind of under utilizing resources but it has the benefit of being completely siloed so the next logical step if you want to leverage compute and maximize compute is have each tenant use the same app the same compute resources and then behind that your app will decide depending on the tenant which database to go to so databases are siloed your data siloed but the actual compute is shared so you're leveraging more of your app compute between tenants and then siloing out for their data another option is just partitioning the data so instead of having silo data instead we have the same database or same data storage but rather what we're doing is each tenant is leveraging the same instance or the same database and what this means is for example if we're talking about a relational database but this could be a document database the same type of thing is that we're segregating data and partitioning data within that data storage so in this case of say an order table we have a tenant id an order id and the rest of our columns but that tenant id is that partition key that's how we're partitioning our data is by a tenant so we can see that the first and third records are for a particular tenant t1 as just i described it here and our other data is for different uh tenants so meaning that we have data for various tenants all within the same data storage but we're partitioning them by this tenant id so regardless of whether you're pooling your data or you're partitioning your data or really your compute for that matter too a lot of this comes down to identity in understanding a request in the kind of the context of the request for what partition what tenant it belongs to so this means that if we're talking about an api that's our computer service when our user logs in hits our identity service that token that we're giving back to it some type of key contains some identity that can tell us what the tenant id is that we're particularly partitioning on or however we're siloed that means that when we make a request to our compute we're sending that key along there and if we're using that key in a partition sense when we make that request to say select a particular set of data we're using that tenant id as our partition key just like in the table this i described before to only return the relevant records and i'll show an example of this later in net and c sharp so if we're talking about it being siloed the same type of thing happens here is that we're giving our key back to our user or whatever our client is that when we send back to compute our compute can decide at that point okay based on the tenant i know i'm going to this database or i need this connection string so i can decide that at that point so regardless of whether it's pooled or partitioned having identity of what the tenant is that's who's the the context of making the request is really important so as an example what that looks like in code specifically with entity framework in c sharp is that i have this order db context and it takes a token inside the token i have a tenant id so that has to get passed to the constructor of our order db context in the on model creating what i have here is this is built into ef core is that we have this query filter and what this means is that any queries that we perform on our order model here data model is that it's going to automatically filter it by that tenant id that we provided in our token so what i've done here as an uh to illustrate this is i've just written some tests here and to even go farther to illustrate this how this works with a service collection is just you're creating you're basically registering a delegate which i've created as the tenant factory um going to create our new instance and our usage actually looks like this is that we're basically creating a new instance of our database with the factory passing in the token so again any query that we make automatically is going to be filtering by our partition key which is our tenant id so as we can see in our test here i basically have tenant one where i'm just creating a new grid as the tenant id i'm adding an order i do the same thing for another tenant with a completely different grid and then when i fetch out orders i have no filter here when i fetch out the orders i actually only get one these two orders are never returned as a part of our filter because it's automatically built in with this query filter if your data was siloed this would be fairly similar is that instead of having the query filter when you're connecting and creating your instance you'd be wanting to change what the connection string is to point to the right instance based off the tenant now obviously this has some logic around it and how you do this whether you want to reach out to a separate service to figure out what the connection string is i'd much prefer having something stateless where i didn't have to add that latency and potential failure there to reach out to another service but again the model still the same here is that you need identity you need context of the user making the requests so that you can make the appropriate call whether it's be a query filter or a connection another option is using hypermedia and i'm going to show this in two different ways the first is with an http api so when our client makes a request to our identity service and it gets back that token that identifies like we're mentioning before our tenant it's also going to identify what hosts we're actually making our http requests to because since we're not building our actual uris this information is provided to us so a part of that response is where you're saying you're going to be hitting for example app1.foo.com and that's a particular app compute and data storage in its own particular lane so when we make our request just like we're normally doing we're making it to specifically now app1.foo.com and it's going to just hit that data storage now again this data storage at this point could be siloed in my example maybe it's not maybe it's partitioned but we're basically leveraging telling the client where what the host is it's actually going to hit which can be we could scale this out infinitely to have different hosts for different tenants if you're not creating hp apis but rather you have something like mvc we're actually serving html this means when a user physically goes in their browser and goes to log into your system to the main part of your site once you've authenticated them you're then redirecting them to the appropriate hosts for that tenant that means that once they log in they'll be redirected to app.foo.com this means that all their traffic at that point is going through that lane the benefit of this approach whether it's an hp api or it's just html like on a regular web app is that these lanes allow you some flexibility in terms of deployment when you decide to publish an update you can be doing so to app1.foo.com and see how that resonates or maybe there's some experiment you want to do in that particular part of the app and it's not affecting all of your tenants you're doing this kind of on a lane by lane basis and deciding okay there's these x amount of tenants that we're going to experiment with or try a new feature on or even just we're deploying and we want to make sure that everything's fine there you can do that to kind of one lane one grouping at a time so hopefully this illustrated there are many different ways to deal with a multi-tenant environment you can silo data you can partition data you can pool compute you can pool compute by a set of tenants and create different lanes there are a lot of different options things that i didn't even mention like just having kind of a load balancer or reverse proxy make decisions based on various rules i was kind of illustrating it just at your browser level with different hosts but there's many different ways to do this one key factor for me though is making your application and while you're writing your application code that you don't have to think about this so in my example where i had any framework using the query filter in a partition kind of environment but you could do the same type of thing like i mentioned so when you create your instance you're just passing in what the token is so you know what the tenant id is so whether you can do the um the query filter or connect to a specific instance you don't want to be thinking about this while you're writing code while you're writing your application code you want this to be seamless you have a token you pass it in you get your context out you don't have to think about writing a particular where clause or how you're getting data out it just feels like you're always in a siloed environment if you found this video helpful please give it a thumbs up if you have any thoughts or questions make sure to leave a comment and please subscribe for more videos on software architecture and design thanks you
Info
Channel: CodeOpinion
Views: 10,785
Rating: undefined out of 5
Keywords: multi-tenant architecture, software architecture, software design, design patterns, software architect, soa, microservices, event bus, event driven architecture, service bus, message queuing, messaging patterns, service oriented architecture, microservice architecture, domain-driven design, multi-tenant archetecture, multi tenant architecture, multi tenant, multi-tenant, asp.net multi-tenant, .net multi tenant, entity framework multi tenant, Ef core mult-tenant
Id: e8k6TynqGFs
Channel Id: undefined
Length: 11min 6sec (666 seconds)
Published: Wed Sep 22 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.