无长锁的django迁移

zero-downtime-migrations的Python项目详细描述


PyPI VersionSupported Python versionsBuild Status

零停机迁移

说明

零停机迁移(zdm)–这是一个允许您避免长锁(和重写整个表)的应用程序。 使用postgresql作为数据库应用django迁移时。

当前可能性

  • 使用默认值添加字段(是否可为空)
  • 同时创建索引(如果索引状态无效,则在创建后检查索引状态)
  • 通过同时创建唯一索引并使用该索引< /LI>创建约束,向现有字段添加唯一属性

为什么使用它

我们面临这样一个问题-执行一些django迁移(例如使用默认值添加列)将表锁定在 读/写,因此在此期间我们的服务无法正常工作。在很小的地方也可以接受 表(少于一百万行),但即使在表上,如果服务负载很高,也会很痛苦。 但是我们有很多超过5000万行的表,在这样的表上应用迁移可以锁定它 一个多小时,这是完全不能接受的。而且,在这个耗时的操作中,迁移常常会失败 因为有不同的错误(比如timeouterror),我们必须从头开始,或者手动运行sql psql和假迁移时。

所以最后我们有了编写这个包的想法,这样它可以防止表上的长锁,而且 提供更稳定的迁移过程,如果由于某种原因操作失败,则可以继续迁移。

安装

要安装ZDM,只需运行:

pip install zero-downtime-migrations

使用量

如果您当前正在使用默认PostResql后端,请将其更改为:

DATABASES = {
     'default': {
         'ENGINE': 'zero_downtime_migrations.backend',
         ...
     }
     ...
 }

如果您使用自己的自定义后端,则可以:

  • 如果当前正在使用默认值,请设置SchemaEditorClass
from zero_downtime_migrations.backend.schema import DatabaseSchemaEditor

class DatabaseWrapper(BaseWrapper):
    SchemaEditorClass = DatabaseSchemaEditor
  • 如果您使用自定义类,请将ZeroDownTimeMixin添加到DatabaseSchemaEditor的基类中:
from zero_downtime_migrations.backend.schema import ZeroDownTimeMixin

class YourCustomSchemaEditor(ZeroDownTimeMixin, ...):
    ...

关于索引

的说明

库将始终强制并发创建索引,并在创建索引后检查索引状态-如果索引是 创建时状态无效,将被删除并引发错误。 在这种情况下,如果需要,您应该修复问题并重新启动迁移。 例如,如果创建唯一索引失败,则应确保只有唯一值 正在创建索引的列中。 由于死锁,通常索引创建的状态无效,因此您只需重新启动迁移即可。

示例

当使用默认django添加not null列时,将执行这样的sql查询:

ALTER TABLE "test" ADD COLUMN "field" boolean DEFAULT True NOT NULL;

这会导致PistGRE重写整个表,当与现有表交换时(^ {A4}) 在此期间,它将对此表的写/读保持独占锁。

这个包将在单独的命令中中断上面的sql,这不仅是为了防止重写整个 表中还要添加尽可能小的锁时间列。

首先,我们将在一个事务中添加无默认值的可空列,并在单独的命令中添加默认值:

ALTER TABLE "test" ADD COLUMN "field" boolean NULL;
ALTER TABLE "test" ALTER COLUMN "field" SET DEFAULT true;

这将为表中的所有新行添加默认值,但所有现有的列将在该列中以空值为单位, 此操作将很快,因为PASGRESs不必以默认方式填充所有现有行。

接下来我们将计算表中的对象,如果结果大于零,则计算 我们将更新现有行的批量大小。在那之后,这里还有空值的对象 列-我们将更新它们。

当下列语句的结果大于零时:

WITH cte AS (
SELECT <table_pk_column> as pk
FROM "test"
WHERE  "field" is null
LIMIT  <size_calculated_on_previous_step>
)
UPDATE "test" table_
SET "field" = true
FROM   cte
WHERE  table_.<table_pk_column> = cte.pk

当我们在这个列中没有空的行时,我们可以设置not null并删除default(这是django default 行为):

ALTER TABLE "test" ALTER COLUMN "field" SET NOT NULL;
ALTER TABLE "test" ALTER COLUMN "field" DROP DEFAULT;

所以我们完成了添加字段的过程。 会的显然比使用一条sql语句的基本变量更耗时,但是在这种方法中 表上没有长锁,因此服务可以在此迁移过程中正常工作。

运行测试

./run_tests.sh

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java JavaFX触控事件未触发Ubuntu 20.04触控笔记本电脑   java如何在AWT中关闭窗口?   java Dagger 2:注入具有构造函数参数的成员   创建对象的Java调用类   对象我想在A.java中添加两个数字,并在B.java中打印结果(如何?)   java如何使用AWS SDK for Android从数字海洋空间下载图像?   java Facebook sdk 4.0.1无法使用Android studio获取某些字段   4分钟后web应用程序(Angular 8和Rest API)中的java自动会话超时   在Eclipse for Java EE developers edition中禁用HTML警告   java按字母顺序排列字符串我错过了什么明显的东西吗?   java在Jshell中println和printf有什么不同