【问题标题】:optimal architecture for multitenant application on djangodjango 上多租户应用程序的最佳架构
【发布时间】:2011-11-03 21:25:47
【问题描述】:

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

一些解释:

  • 应用程序可由多个租户(租户 1、租户 2、...)使用。

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

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

  • 当然,底层硬件限制了一个“系统”上的租户数量。

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

2) 在模型中使用一些租户 ID 来分隔数据库中的租户数据

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

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

你怎么看?

【问题讨论】:

  • 如果我能对此投票一百次,我会的。
  • 谢谢 :-) 任何想法或其他方面,我没有提到?
  • Django 内置了 Sites 框架,我认为可以对其进行扩展以提供更好的多租户支持。需要有一种方法来识别我们需要从请求中的某些内容中提取内容的“站点”,而不是在 settings.py 中硬编码哪个站点
  • 无 sql 支持也可以让多租户变得更容易,但是,目前我知道没有一个好的方法来判断特定站点的数据位于哪个分片上。
  • 在研究了使用 Sites 框架后,我得出的结论是,它的目的是让不同站点之间的数据共享更容易——这与你想要的多租户应用程序完全相反,出于数据安全原因。

标签: django architecture multi-tenant


【解决方案1】:

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

  • 每个租户都有子域 (t1.example.com)
  • 使用 url 重写 Django 应用程序的请求被重写为 example.com/t1 之类的内容
  • 所有 url 定义都以 (r'^(?P<tenant_id>[\w\-]+) 之类的前缀
  • middleware 处理和使用tenant_id 并将其添加到请求中(例如 request.tenant = 't1')
  • 现在您可以在每个视图中使用当前租户,而无需在每个视图中指定tenant_id 参数
  • 在某些情况下,您没有可用的请求。我通过将tenant_id 绑定到当前线程解决了这个问题(类似于使用threading.localcurrent language
  • 创建装饰器(例如租户感知 login_required)、中间件或工厂以保护视图并选择正确的模型
  • 关于数据库,我使用了两种不同的方案:
    • 根据当前租户设置多个数据库并配置routing。我首先使用它,但大约一年后切换到一个数据库。原因如下:
      • 我们不需要高度安全的解决方案来分离数据
      • 不同的租户使用几乎所有相同的模型
      • 我们必须管理大量数据库(并且没有构建简单的更新/迁移流程)
    • 使用带有一些简单映射表的数据库,即用户和不同的模型。要添加额外的租户特定模型字段,我们使用model inheritance

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

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

专业版:

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

反对:

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

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

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

【讨论】:

  • 非常感谢。对于指定的应用程序,清晰和安全的数据分离是非常重要的。我还认为大约 70% 的模型对所有租户都是相同的。
  • 那么我建议您使用带有自动路由的多数据库设置。我会使用south 来管理数据库,因为它们现在支持多个数据库。
  • 谢谢。实际上,我更喜欢多个数据库设置,因为分离更清晰,将租户转移到其他数据库服务器可能更容易......南方已经放在我的技术堆栈中用于迁移任务......
  • 这个解决方案仍然可行吗?我在不同的地方读到人们不应该依赖 threading.local(不再)。
  • 你是如何做到第一点的(每个租户获得子域(t1.example.com))..如何在本地机器和生产服务器上实现它?
【解决方案2】:

我建议看看https://github.com/bcarneiro/django-tenant-schemas。它将像 Reto 提到的那样解决您的问题,除了它使用 postgresql 模式。

【讨论】:

    【解决方案3】:

    以下是相关讨论的一些提示:

    【讨论】:

      猜你喜欢
      • 2015-08-21
      • 2017-01-07
      • 1970-01-01
      • 2011-06-01
      • 2014-01-26
      • 1970-01-01
      • 2014-07-18
      • 2011-02-27
      • 2015-01-05
      相关资源
      最近更新 更多