.net 多租户程序框架_如果您有公寓,构建多租户应用程序很容易!

.net 多租户程序框架

by Igor Petrov

通过伊戈尔·彼得罗夫(Igor Petrov)

如果您有公寓,构建多租户应用程序很容易! (Building a multi-tenant app is easy…if you have an apartment!)

These days, more and more startups are appearing on the SaaS market. For their apps, they have several development approaches to choose from. And one of the technical models is the multi-tenancy or multi-tenant app. If you’re going to share all your software with your startup customers — either with the ability to have separate data/content and URLs (say, SaaS), or just part of it — you need a multi-tenant app.

如今,越来越多的初创公司出现在SaaS市场上。 对于他们的应用程序,他们有几种开发方法可供选择。 技术模型之一是多租户 或多租户应用程序。 如果您打算与初创客户共享所有软件,或者具有单独的数据/内容和URL(例如SaaS )的能力,或者只是其中一部分,则需要多租户应用程序。

This is not the only choice: I should mention other approaches, but let’s just mention them — a comparison of different approaches could be a good topic for the next article.

这不是唯一的选择:我应该提及其他方法,而让我们仅提及它们-比较不同的方法可能是下一篇文章的好话题。

Here is my list (ordered by implementation complexity):

这是我的列表(按实现复杂度排序):

  • URL path-based SaaS. Easiest one. Single domain, single DB, etc. Application-level restrictions for data.

    基于URL路径的SaaS 。 最简单的一个。 单个域,单个DB等。数据的应用程序级别限制。

  • Multi-tenant SaaS. Medium complexity. Subdomain-based or domain-based. Multiple databases or schemas. Database-level restrictions for data.

    多租户SaaS 。 中等复杂度。 基于子域或基于域。 多个数据库或架构。 数据库级别的数据限制。

  • Virtualization-based SaaS (thanks to Docker and friends!). High level of complexity. Subdomain/domain-based. Multiple apps and DB copies. Virtualization-level restrictions for data.

    基于虚拟化的SaaS (感谢Docker和朋友!)。 高度复杂。 子域/基于域。 多个应用程序和数据库副本。 数据的虚拟化级别限制。

多租户 (Multi-tenancy)

So what is multi-tenancy? Multi-tenancy is a software development architecture approach in which each client gets their own app configuration and data (strictly or softly isolated from other clients). Each “instance” is called a “tenant.

那么什么是多租户多租户是一种软件开发体系结构方法,其中每个客户端都可以获取自己的应用程序配置和数据(与其他客户端严格或隔离)。 每个“实例”都称为“ 租户”。

Over the past few years, I’ve worked on several multi-tenant apps (I mostly did multi-tenancy from scratch). And even now, I’m working on two multi-tenant apps.

在过去的几年中,我从事过多个多租户应用程序(我大部分都是从头开始做多租户 )。 甚至现在,我仍在开发两个多租户应用程序。

Let’s move on from the introduction and theory to the practice, and look at what could be used for multi-tenant apps in the world of Ruby on Rails.

让我们从介绍和理论转向实践,然后看看Ruby on Rails世界中可用于多租户应用程序的内容。

公寓式 (Apartment)

This is number one for Ruby on Rails apps. Let’s add it to Gemfile:

这是Ruby on Rails应用程序的第一名。 让我们将其添加到Gemfile中

gem ‘apartment’

After bundle install you need to run a generator so you’ll get some basic configuration templates:

bundle install后,您需要运行生成器,以便获得一些基本的配置模板:

bundle exec rails generate apartment:install

Now you have config/initializers/apartment.rb where you can tweak how you want to use Apartment. The most important things that should be configured are: how “apartment” will know how to identify your tenants for storing data (we’ll assume it’s a PostgreSQL database where each PostgreSQL schema is a separate tenant), and how to show data depending on HTTP requests.

现在,您有了config/initializers/apartment.rb ,可以在其中调整如何使用Apartment 。 应该配置的最重要的事情是:“ 公寓 ”将如何知道如何标识您的租户以存储数据(我们假设这是一个PostgreSQL数据库,其中每个PostgreSQL模式都是一个单独的租户),以及如何根据HTTP请求。

Ok, in one app I’m developing I have a Website ActiveRecord model with slug field. Therefore, the first setting looks like this, and each website is a tenant:

好吧,在一个应用程序,我发展我有一个WebsiteActiveRecord模型slug场。 因此,第一个设置如下所示,每个网站都是一个租户

config.tenant_names = lambda { Website.pluck(:slug) }

Let’s say I decided to treat any subdomain as the website’s slug. So if I have a Website with my-awesome-website slug, then my-awesome-website.example.com will serve data from my-awesome-data DB schema. To have this behavior we need:

假设我决定将任何子域都视为网站的子弹。 因此,如果我的Websitemy-awesome-websiteWebsite my-awesome-website ,那么my-awesome-website.example.com将提供来自my-awesome-data数据库架构my-awesome-data 。 要具有这种行为,我们需要:

# require 'apartment/elevators/subdomain'
...Rails.application.config.middleware.use Apartment::Elevators::Subdomain

The third setting you might need is excluding some models that should be shared across all tenants. Like Website itself from my example:

您可能需要的第三个设置是排除应在所有租户之间共享的某些模型。 从我的示例中类似Website本身:

config.excluded_models = %w{ Customer Website Plan Feature PlanFeature }

进阶技巧 (Advanced tips)

自定义电梯类 (Custom Elevator Class)

Ok, we’ve built a subdomain-based multi-tenant app, but what if we need a custom domains feature for our customers? But it still should be accessible from the subdomain as well. Then we need a custom elevator class — similar to what we’ve used above — Apartment::Elevators::Subdomain .

好的,我们已经构建了一个基于子域的多租户应用程序,但是如果我们需要为客户提供自定义域功能怎么办? 但是仍然应该可以从子域访问它。 然后,我们需要一个自定义的电梯类(类似于我们上面使用的类): Apartment::Elevators::Subdomain

Elevator class should decide, based on the current request, what tenant (database/schema) should be used. In case we have a domain field on the Website model:

电梯类应根据当前请求决定应使用哪种租户 (数据库/架构)。 如果我们在“ Website模型上有一个domain字段:

Here we’ve created a custom elevator class (in lib/apartment/elevators/active_website.rb) inherited from Subdomain elevator and overridden by parse_tenant_name that should return tenant name based on a request. So first we call super and save the result in tenant variable. If we have a website with the domain set up as a requested domain, we’ll return such a slug (tenant). Otherwise, we fall back to subdomain.

在这里,我们创建了一个自定义电梯类(在lib/apartment/elevators/active_website.rb ), lib/apartment/elevators/active_website.rb继承自Subdomain电梯,并被parse_tenant_name覆盖, parse_tenant_name应根据请求返回租户名称。 因此,首先我们调用super并将结果保存在tenant变量中。 如果我们有一个将域名设置为请求域名的网站,则将返回这样的信息( 租户 )。 否则,我们将退回到子域。

找不到页面的不正确租户 (Not Found Page for incorrect tenants)

Task #2: what if some non-existent tenant was requested? Someone makes a request to no-such-tenant.example.com, but we don’t have such a database schema. The best thing we could do is to respond with some 404 page. This task is not about apartment directly, but is closely related.

任务2:如果请求一些不存在的租户怎么办? 有人向no-such-tenant.example.com发出请求,但是我们没有这样的数据库架构。 我们最好的办法是响应一些404页面。 该任务不是直接与apartment有关,而是紧密相关。

We’ll enhance our elevator class like this:

我们将像这样增强我们的电梯课程:

What is ::NotFound you may ask? This is a simple middleware that I use for this purpose. Placed in app/middlewares it’s written as below:

您可能会问什么是::NotFound ? 这是我用于此目的的简单中间件。 放置在app/middlewares的代码如下:

Task solved — client is happy!

解决的任务-客户满意!

排除的子域 (Excluded Subdomains)

If you need one or several subdomains to treat as a public tenant (not a client’s) and not to switch on requests for it, you would use the excluded_subdomains option. This option is available for Subdomain elevator and its subclasses of course:

如果您需要一个或几个子域作为公共租户 (而不是客户的租户 )并且不打开对它的请求,则可以使用excluded_subdomains选项。 当然,此选项可用于Subdomain电梯及其子类:

Apartment::Elevators::ActiveWebsite.excluded_subdomains = ['app']
播种数据 (Seeding data)

If your tenants are already created, you could initialize them with data using db/seeds.rb. With rails db:seed it will be applied to each tenant.

如果已经创建了租户,则可以使用db/seeds.rb使用数据初始化它们。 使用rails db:seed它将应用于每个租户。

But what if you need to initialize a just-created tenant (via Apartment::Tenant.create) with some data programmatically? Well, you could still do this by switching to tenant and creating some models (or executing the Rake task programmatically).

但是,如果您需要通过编程以一些数据初始化刚创建的租户 (通过Apartment::Tenant.create )呢? 好的,您仍然可以通过切换到租户并创建一些模型(或以编程方式执行Rake任务)来做到这一点。

Look how spree_shared gem does this for popular spree gem (the code below is an updated version because spree_shared doesn’t work with the current Spree version):

查看spree_shared gem如何为流行的spree gem做到这一点(以下代码是更新版本,因为spree_shared不适用于当前的Spree版本):

If you need seeds to be applied to each tenant, you might write it this way (again, a modified example from spree_shared):

如果需要将种子应用于每个租户 ,则可以这样编写(再次,从spree_shared修改示例):

将租户创建包装到交易中 (Wrapping tenant creation into transaction)

The next step is wrapping the tenant creation into the transaction block, because we know that every tenant has a corresponding database model (Website or Customer ), and we want to make sure both the model instance and the tenant were created. This will make our app more transactional, and we won’t have a DB tenant without the corresponding model instance or vice versa.

下一步是将承租人创建包装到事务块中,因为我们知道每个承租人都有一个对应的数据库模型( WebsiteCustomer ),并且我们要确保同时创建了模型实例和承租人 。 这将使我们的应用程序更具事务性,没有相应的模型实例,我们将没有数据库租户 ,反之亦然。

Service Objects comes to the rescue! For our hosted websites app, we might write something like this:

服务对象可助您一臂之力! 对于我们的托管网站应用程序,我们可能会这样写:

We need to handle possible exceptions: if a record or tenant wasn’t created for some reason.

我们需要处理可能的异常:如果由于某种原因未创建记录或租户

结论 (Conclusion)

Well, as you may see, developing multi-tenant apps is easy enough if you have good tools like the apartment gem. Let me know in the comments your cases of apartment appliance. Especially non-standard ones.

好了,如您所见,如果您拥有apartment gem之类的良好工具,那么开发多租户应用程序就很容易。 请在评论中让我知道您的apartment设备案例。 特别是非标准的。

翻译自: https://www.freecodecamp.org/news/building-a-multi-tenant-app-is-easy-if-you-have-an-apartment-3465f6eda85b/

.net 多租户程序框架

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值