django 上多租户应用程序的最佳架构 [英] optimal architecture for multitenant application on django

查看:30
本文介绍了django 上多租户应用程序的最佳架构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在思考创建基于多租户应用程序的正确/最佳方式在 Django 上.

I've been brooding over the right/optimal way to create a multitenancy application based on Django.

一些解释:

  • 应用程序可以被多个租户使用(tenant1、tenant2、...、).

  • Application can be used by several tenants (tenant1, tenant2, ...,).

必须保护所有租户个人数据,防止其他租户(及其用户)访问.

All tenant-individual data has to be secured against access of other tenants (and their users).

租户可以选择为应用程序对象创建额外的自定义字段.

Optionally tenants can create additional custom-fields for application-objects.

当然,底层硬件限制了一个系统"上的租户数量.

Of course, underlying hardware limits number of tenants on one "system".

1) 通过例如分隔每个租户子域并在底层使用租户特定的数据库

1) Separating each tenant by e.g. sub-domain and using tenant-specific databases in the underlying layer

2) 使用模型中的一些tenant-ID来分离数据库中的tenant-data

2) Using some tenant-ID in the model to separate the tenant-data in the database

我正在考虑部署流程、系统部件的性能(网络服务器、数据库服务器、工作节点……)

I am thinking about deployment-processes, performance of the system-parts (web-server(s), database-server(s), working-node(s),...)

最好的设置是什么?优点和缺点在哪里?

What would be the best setup ? Where are the pro's and con's?

你怎么看?

推荐答案

我们构建了一个多租户平台使用以下架构.我希望你能找到一些有用的提示.

We built a multitenancy platform using the following architecture. I hope you can find some useful hints.

  • 每个租户获得子域 (t1.example.com)
  • 使用 url 重写 Django 应用程序的请求被重写为类似 example.com/t1 的内容
  • 所有 url 定义都以 (r'^(?P<tenant_id>[\w\-]+)
  • 为前缀
  • A 中间件进程并使用租户 ID 并将其添加到请求中(例如 request.tenant = 't1')
  • 现在您可以在每个视图中使用当前租户,而无需在每个视图中指定tenant_id 参数
  • 在某些情况下,您没有可用的请求.我通过将tenant_id绑定到当前线程解决了这个问题(类似于当前语言 使用 threading.local )
  • 创建装饰器(例如租户感知login_required)、中间件或工厂以保护视图并选择正确的模型
  • 关于数据库,我使用了两种不同的场景:
    • 设置多个数据库并配置一个路由 根据当前租户.我首先使用它,但大约一年后切换到一个数据库.原因如下:
      • 我们不需要高度安全的解决方案来分离数据
      • 不同的租户使用几乎所有相同的模型
      • 我们不得不管理大量数据库(并且没有构建简单的更新/迁移流程)
      • Each tenant gets sub-domain (t1.example.com)
      • Using url rewriting the requests for the Django application are rewritten to something like example.com/t1
      • All url definitions are prefixed with something like (r'^(?P<tenant_id>[\w\-]+)
      • A middleware processes and consumes the tenant_id and adds it to the request (e.g. request.tenant = 't1')
      • Now you have the current tenant available in each view without specifying the tenant_id argument every view
      • In some cases you don't have the request available. I solved this issue by binding the tenant_id to the current thread (similar to the current language using threading.local )
      • Create decorators (e.g a tenant aware login_required), middlewares or factories to protect views and select the right models
      • Regarding to the databases I used two different scenarios:
        • Setup multiple databases and configure a routing according to current tenant. I used this first but switched to one database after about one year. The reasons were the following:
          • We didn't need a high secure solution to separate the data
          • The different tenants used almost all the same models
          • We had to manage a lot of databases (and didn't built an easy update/migration process)

          关于环境,我们使用以下设置:

          Regarding the environment we use the following setup:

          在我看来,这种设置有以下优点和缺点:

          From my point of view this setup has the following pro's and con's:

          专业:

          • 一个知道当前租户的应用程序实例
          • 项目的大部分内容都不必为租户的特定问题而烦恼
          • 在所有租户之间共享实体的简单解决方案(例如消息)

          反对:

          • 一个相当大的数据库
          • 由于模型继承,一些非常相似的表
          • 在数据库层没有保护

          当然,最佳架构在很大程度上取决于您的要求,如租户数量、模型的增量、安全要求等.

          Of course the best architecture strongly depends on your requirements as number of tenants, the delta of your models, security requirements and so on.

          更新:在我们审查我们的架构时,我建议不要重写第 2-3 点中所示的 URL.我认为更好的解决方案是将 tenant_id 作为请求标头并使用 request.META 之类的内容从请求中提取(第 4 点)tenant_id.get('TENANT_ID', None).通过这种方式,您可以获得中性 URL,并且可以更轻松地使用 Django 内置函数(例如 {% url ...%}reverse())或外部应用程序.

          Update: As we reviewed our architecture, I suggest to not rewrite the URL as indicated in point 2-3. I think a better solutions is to put the tenant_id as a Request Header and extract (point 4) the tenant_id out of the request with something like request.META.get('TENANT_ID', None). This way you get neutral URLs and it's much easier to use Django built-in functions (e.g. {% url ...%} or reverse()) or external apps.

          这篇关于django 上多租户应用程序的最佳架构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆