对多租户的Django应用的最佳架构 [英] optimal architecture for multitenant application on 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)在模型中使用的一些租户ID为租户数据库中的数据分开
2) Using some tenant-ID in the model to separate the tenant-data in the database
我想有关部署流程,系统部件的性能(Web服务器(S),数据库服务器(S),工作节点上,...)
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定义的东西pfixed像
$ P $(R'^(P< tenant_id>?[\\ W \\ - ] +)
- A <一个href=\"https://docs.djangoproject.com/en/1.3/topics/http/middleware/#writing-your-own-middleware\">middleware流程和消耗tenant_id并将其添加到请求(例如request.tenant ='T1')
- 现在,你必须在每个视图提供当前租户不指定tenant_id参数每个视图
- 在某些情况下,你没有可用的请求。我由tenant_id结合到当前线程(类似于当前语言解决了这个问题使用
threading.local
) - 创建装饰(如承租人意识到
login_required
),中间件或工厂,以保护意见,并选择合适的机型 - 关于给我用了两个不同的方案数据库:
- 设置多个数据库和配置<一href=\"https://docs.djangoproject.com/en/dev/topics/db/multi-db/#automatic-database-routing\">routing根据目前的租户。我用这个第一,但约一年后,切换到一个数据库。究其原因有以下几条:
- 我们并不需要一个高安全的解决方案将数据分隔
- 不同的租户使用的几乎所有的同款
- 我们必须管理大量的数据库(并没有建立一个简单的升级/迁移过程)
- 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:
- Nginx的
- uWSGI
- 的PostgreSQL
- Memcached的
- Nginx
- uWSGI
- PostgreSQL
- Memcached
从我的角度来看这个设置具有以下亲的和反对的:
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.
更新:当我们回顾我们的架构,我建议的不的重写URL作为点2-3所示。我认为,一个更好的解决方案是把
tenant_id
作为一个请求头,并提取(4点)的tenant_id
出喜欢的东西request.META.get('TENANT_ID',无)请求
。这样,你得到的中性URL和它更容易使用Django的内置函数(如{%网址...%}
或反向()
)或外部应用程序。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) thetenant_id
out of the request with something likerequest.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 ...%}
orreverse()
) or external apps.这篇关于对多租户的Django应用的最佳架构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- 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:
- 设置多个数据库和配置<一href=\"https://docs.djangoproject.com/en/dev/topics/db/multi-db/#automatic-database-routing\">routing根据目前的租户。我用这个第一,但约一年后,切换到一个数据库。究其原因有以下几条: