在 确定分布策略 中,我们讨论了在多租户用例中使用 Citus 所需的与框架无关的数据库更改。 在这里,我们专门研究如何借助 django-multitenant 库将多租户 Django
应
用程序迁移到 Citus 存储后端。
- Django
- 确定分布策略
- django-multitenant
此过程将分为 5 个步骤:
- 将租户列介绍给我们想要分发的缺少它的模型
- 更改分布式表的主键以包含租户列
- 更新模型以使用
TenantModelMixin
- 分发数据
- 将
Django
应用程序更新为范围查询
准备横向扩展多租户应用程序
最初,您将从放置在单个数据库节点上的所有租户开始。 为了能够扩展 django
,必须对模型进行一些简单的更改。
让我们考虑这个简化的模型:
from django.utils import timezone
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=255)
class Account(models.Model):
name = models.CharField(max_length=255)
domain = models.CharField(max_length=255)
subdomain = models.CharField(max_length=255)
country = models.ForeignKey(Country, on_delete=models.SET_NULL)
class Manager(models.Model):
name = models.CharField(max_length=255)
account = models.ForeignKey(Account, on_delete=models.CASCADE,
related_name='managers')
class Project(models.Model):
name = models.CharField(max_length=255)
account = models.ForeignKey(Account, related_name='projects',
on_delete=models.CASCADE)
managers = models.ManyToManyField(Manager)
class Task(models.Model):
name = models.CharField(max_length=255)
project = models.ForeignKey(Project, on_delete=models.CASCADE,
related_name='tasks')
这种模式的棘手之处在于,为了找到一个帐户的所有任务,您必须首先查询一个帐户的所有项目。 一旦您开始分片数据,这就会成为一个问题,特别是当您对嵌套模型(如本例中的任务)运行 UPDATE
或 DELETE
查询时。
1. 将租户列引入属于帐户的模型
1.1 向属于某个帐户的模型引入该列
为了扩展多租户模型,查询必须快速定位属于一个帐户的所有记录。考虑一个 ORM
调用,例如:
Project.objects.filter(account_id=1).prefetch_related('tasks')
它生成这些底层 SQL
查询:
SELECT *
FROM myapp_project
WHERE account_id = 1;
SELECT *
FROM myapp_task
WHERE project_id IN (1, 2, 3);
但是,使用额外的过滤器,第二个查询会更快:
-- the AND clause identifies the tenant
SELECT *
FROM myapp_task
WHERE project_id IN (1, 2, 3)
AND account_id = 1;
这样您就可以轻松查询属于一个帐户的任务。 实现这一点的最简单方法是在属于帐户的每个对象上简单地添加一个 account_id
列。
在我们的例子中: