django多租户应用的最佳体系结构

我一直沉迷于正确/最佳的方式来创build一个基于Django的多租户应用程序。

一些解释:

  • 应用程序可以由几个租户(tenant1,tenant2,…)使用。

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

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

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

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

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

我正在考虑部署过程,系统部分(networking服务器,数据库服务器,工作节点等)的性能。

什么是最好的设置? 亲和骗子在哪里?

你怎么看?

我们使用以下架构构build了多租户平台 。 我希望你能find一些有用的提示。

  • 每个租户都获得子域(t1.example.com)
  • 使用url重写Django应用程序的请求被重写为example.com/t1
  • 所有的url定义都以(r'^(?P<tenant_id>[\w\-]+)
  • 中间件处理并使用tenant_id并将其添加到请求中(例如,request.tenant ='t1')
  • 现在,您可以在每个视图中使用当前租户,而无需在每个视图中指定tenant_id参数
  • 在某些情况下,您没有可用的请求。 我通过将tenant_id绑定到当前线程来解决这个问题(类似于使用threading.local的当前语言 )
  • 创build装饰器(例如承租人知道的login_required请求),中间件或工厂来保护视图并select正确的模型
  • 关于数据库,我使用了两种不同的情况:
    • 根据当前租户设置多个数据库并configuration路由 。 我首先使用了这个function,但是大约一年后就切换到一个数据库了 原因如下:
      • 我们不需要高度安全的解决scheme来分离数据
      • 不同的租户使用几乎所有相同的模型
      • 我们必须pipe理很多数据库(并没有build立一个简单的更新/迁移过程)
    • 使用一个数据库与一些简单的映射表,即用户和不同的模型。 要添加其他特定于租户的模型字段,我们使用模型inheritance 。

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

  • Nginx的
  • uWSGI
  • PostgreSQL的
  • Memcached的

从我的angular度来看,这个设置有以下的亲和骗局:

优点:

  • 一个应用程序实例知道当前的租户
  • 项目的大部分内容都不必担心佃户的具体问题
  • 所有租户之间共享实体的简单解决scheme(例如,消息)

魂斗罗:

  • 一个相当大的数据库
  • 一些非常相似的表由于模型的inheritance
  • 在数据库层不安全

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

更新 :正如我们回顾我们的架构,我build议不要重写如第2-3点所示的URL。 我认为更好的解决scheme是将tenant_id作为请求标头,并将请求中的tenant_idrequest.META.get('TENANT_ID', None)提取出来(第4点request.META.get('TENANT_ID', None) 。 这样你就可以获得中立的URL,使用Django内置函数(例如{% url ...%}reverse() )或外部应用程序要容易得多。

以下是有关讨论的一些指示:

  • Django票#15089 :“contrib.sites和multitenancy ”
  • 讨论Google网上论坛 ,详见esp。 贾里·潘纳恩的解决scheme在最后
  • 在Mezzanine中引入基于线程位置的多租户的补丁 ; 见esp。 mezzanine.utils.sites.current_site_idmezzanine.core.models.SiteRelatedmezzanine.core.request
  • PyPI上的django-simple-multitenant可重用应用程序

我build议看一下https://github.com/bcarneiro/django-tenant-schemas 。 它会解决你的问题有点像Reto提到的,只是它使用postgresql模式。