偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Sentry 開(kāi)發(fā)者貢獻(xiàn)指南-數(shù)據(jù)庫(kù)遷移

運(yùn)維 數(shù)據(jù)庫(kù)運(yùn)維
重命名列是危險(xiǎn)的,會(huì)導(dǎo)致停機(jī)。發(fā)生這種情況的原因是在部署期間將運(yùn)行舊/新代碼的混合。因此,一旦我們?cè)?Postgres 中重命名該列,如果舊代碼嘗試訪問(wèn)它,它就會(huì)立即開(kāi)始出錯(cuò)。

Django 遷移是我們處理 Sentry 中數(shù)據(jù)庫(kù)更改的方式。

Django 遷移官方文檔:https://docs.djangoproject.com/en/2.2/topics/migrations/。

這些將涵蓋了解遷移正在執(zhí)行的操作所需的大部分內(nèi)容。

命令

請(qǐng)注意,對(duì)于所有這些命令,如果在 getsentry 存儲(chǔ)庫(kù)中,您可以將 getsentry 替換為 sentry。

將您的數(shù)據(jù)庫(kù)升級(jí)到最新

sentry upgrade 會(huì)自動(dòng)更新你的遷移。您也可以運(yùn)行 sentry django migrate 來(lái)直接訪問(wèn)遷移命令。

將您的數(shù)據(jù)庫(kù)移動(dòng)到特定的遷移

當(dāng)您要測(cè)試遷移時(shí),這會(huì)很有幫助。

sentry django migrate - 請(qǐng)注意,migration_name 可以是部分匹配,通常數(shù)字就是你所需要的。

例如:sentry django migrate sentry 0005

這也可用于回滾遷移。如果你犯了錯(cuò)誤,在開(kāi)發(fā)中很有用。

為遷移生成 SQL

這對(duì)審查您的代碼的人很有幫助,因?yàn)椴⒉豢偸乔宄?Django 遷移實(shí)際要做什么。

sentry django sqlmigrate

例如 sentry django sqlmigrate sentry 0003

生成遷移

這會(huì)根據(jù)您對(duì)模型所做的更改自動(dòng)為您生成遷移。

sentry django makemigrations

或者

sentry django makemigrations 用于一個(gè)指定的 app。

例如 sentry django makemigrations sentry

當(dāng)您在 pr 中包含遷移時(shí),還要為遷移生成 sql 并將其作為注釋包含在內(nèi),以便您的審閱者可以更輕松地了解 Django 正在做什么。

您還可以使用 sentry django makemigrations --empty 生成空遷移。這對(duì)于數(shù)據(jù)遷移和其他自定義工作很有用。

將遷移合并到 master

合并到 master 時(shí),您可能會(huì)注意到與 migrations_lockfile.txt 的沖突。這個(gè)文件是為了幫助我們避免將具有相同遷移編號(hào)的兩個(gè)遷移合并到 master,如果您與它發(fā)生沖突,那么很可能有人在您之前提交了遷移。

指南

在運(yùn)行遷移時(shí),我們需要注意一些事項(xiàng)。

過(guò)濾器

如果(數(shù)據(jù))遷移涉及大表或未索引的列,最好迭代整個(gè)表而不是使用 filter。例如:

  1. EnvironmentProject.objects.filter(environment__name="none"

因?yàn)?EnvironmentProject 行太多,這會(huì)一次將太多行帶入內(nèi)存。相反,我們應(yīng)該使用 RangeQuerySetWrapperWithProgressBar 遍歷所有 EnvironmentProject 行,因?yàn)樗鼤?huì)分塊進(jìn)行。例如:

  1. for env in RangeQuerySetWrapperWithProgressBar(EnvironmentProject.objects.all()): 
  2.     if env.name == 'none'
  3.         # Do what you need 

我們通常更喜歡避免將 .filter 與 RangeQuerySetWrapperWithProgressBar 一起使用。由于它已經(jīng)通過(guò) id 對(duì)表進(jìn)行排序,因此我們無(wú)法利用字段上的任何索引,并且可能會(huì)為每個(gè)塊掃描大量行。這會(huì)運(yùn)行得更慢,但我們通常更喜歡這樣,因?yàn)樗诟L(zhǎng)的時(shí)間內(nèi)平均負(fù)載,并使每個(gè)查詢獲取每個(gè)塊的成本相當(dāng)?shù)汀?/p>

索引

我們更喜歡使用 CREATE INDEX CONCURRENTLY 在現(xiàn)有的大型表上創(chuàng)建索引。當(dāng)我們這樣做時(shí),我們無(wú)法在事務(wù)中運(yùn)行遷移,因此使用 atomic = False 來(lái)運(yùn)行這些很重要。

刪除列/表

由于我們的部署過(guò)程,這很復(fù)雜。當(dāng)我們部署時(shí),我們運(yùn)行遷移,然后推出應(yīng)用程序代碼,這需要一段時(shí)間。這意味著如果我們只是刪除一個(gè)列或模型,那么 sentry 中的代碼將查找這些列/表并在部署完成之前出錯(cuò)。在某些情況下,這可能意味著 Sentry 在部署完成之前很難停機(jī)。

為避免這種情況,請(qǐng)執(zhí)行以下步驟:

  • 如果列不是空的,則將其標(biāo)記為空,并創(chuàng)建一個(gè)遷移。
  • 部署。
  • 從模型中刪除列,但在遷移中確保我們只將狀態(tài)標(biāo)記為已刪除(removed)。
  • 部署。
  • 最后,創(chuàng)建一個(gè)刪除列的遷移。

這是刪除已經(jīng)可以為空的列的示例。首先我們從模型中刪除列,然后修改遷移以僅更新?tīng)顟B(tài)而不進(jìn)行數(shù)據(jù)庫(kù)操作。

  1. operations = [ 
  2.         migrations.SeparateDatabaseAndState( 
  3.             database_operations=[], 
  4.             state_operations=[ 
  5.                 migrations.RemoveField(model_name="alertrule"name="alert_threshold"), 
  6.                 migrations.RemoveField(model_name="alertrule"name="resolve_threshold"), 
  7.                 migrations.RemoveField(model_name="alertrule"name="threshold_type"), 
  8.             ], 
  9.         ) 
  10.     ] 

一旦部署完成,我們就可以部署實(shí)際的列刪除。這個(gè) pr 只會(huì)有一個(gè)遷移,因?yàn)?Django 不再知道這些字段。請(qǐng)注意,反向 SQL 僅適用于開(kāi)發(fā)人員,因此可以不分配默認(rèn)值或進(jìn)行任何類(lèi)型的回填:

  1. operations = [ 
  2.         migrations.SeparateDatabaseAndState( 
  3.             database_operations=[ 
  4.                 migrations.RunSQL( 
  5.                     ""
  6.                     ALTER TABLE "sentry_alertrule" DROP COLUMN "alert_threshold"
  7.                     ALTER TABLE "sentry_alertrule" DROP COLUMN "resolve_threshold"
  8.                     ALTER TABLE "sentry_alertrule" DROP COLUMN "threshold_type"
  9.                     """, 
  10.                     reverse_sql=""
  11.                     ALTER TABLE "sentry_alertrule" ADD COLUMN "alert_threshold" smallint NULL
  12.                     ALTER TABLE "sentry_alertrule" ADD COLUMN "resolve_threshold" int NULL
  13.                     ALTER TABLE "sentry_alertrule" ADD COLUMN "threshold_type" int NULL
  14.  
  15.                     """, 
  16.                 ) 
  17.             ], 
  18.             state_operations=[], 
  19.         ) 
  20.     ] 

如果該表在其他表中被引用為外鍵,則需要格外小心。在這種情況下,首先刪除其他表中的外鍵列,然后返回到此步驟。

  • 通過(guò)在列上設(shè)置 db_constraint=False,刪除此表到其他表的任何數(shù)據(jù)庫(kù)級(jí)外鍵約束。
  • 部署
  • 從 sentry 代碼庫(kù)中刪除模型和所有引用。確保遷移僅將狀態(tài)標(biāo)記為已刪除。
  • 部署。
  • 創(chuàng)建一個(gè)刪除表的遷移。
  • 部署

這是刪除此模型的示例:

  1. class AlertRuleTriggerAction(Model): 
  2.     alert_rule_trigger = FlexibleForeignKey("sentry.AlertRuleTrigger"
  3.     integration = FlexibleForeignKey("sentry.Integration"null=True
  4.     type = models.SmallIntegerField() 
  5.     target_type = models.SmallIntegerField() 
  6.     # Identifier used to perform the action on a given target 
  7.     target_identifier = models.TextField(null=True
  8.     # Human readable name to display in the UI 
  9.     target_display = models.TextField(null=True
  10.     date_added = models.DateTimeField(default=timezone.now) 
  11.  
  12.     class Meta: 
  13.         app_label = "sentry" 
  14.         db_table = "sentry_alertruletriggeraction" 

首先,我們檢查了它沒(méi)有被任何其他模型引用,它沒(méi)有。接下來(lái),我們需要?jiǎng)h除和 db 級(jí)外鍵約束。為此,我們改變這兩列并生成一個(gè)遷移:

  1. alert_rule_trigger = FlexibleForeignKey("sentry.AlertRuleTrigger", db_constraint=False
  2. integration = FlexibleForeignKey("sentry.Integration"null=True, db_constraint=False

遷移中的操作看起來(lái)像

  1. operations = [ 
  2.        migrations.AlterField( 
  3.            model_name='alertruletriggeraction'
  4.            name='alert_rule_trigger'
  5.            field=sentry.db.models.fields.foreignkey.FlexibleForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADEto='sentry.AlertRuleTrigger'), 
  6.        ), 
  7.        migrations.AlterField( 
  8.            model_name='alertruletriggeraction'
  9.            name='integration'
  10.            field=sentry.db.models.fields.foreignkey.FlexibleForeignKey(db_constraint=Falsenull=True, on_delete=django.db.models.deletion.CASCADEto='sentry.Integration'), 
  11.        ), 
  12.    ] 

我們可以看到它生成的 sql 只是刪除了 FK 約束

  1. BEGIN
  2. SET CONSTRAINTS "a875987ae7debe6be88869cb2eebcdc5" IMMEDIATE; ALTER TABLE "sentry_alertruletriggeraction" DROP CONSTRAINT "a875987ae7debe6be88869cb2eebcdc5"
  3. SET CONSTRAINTS "sentry_integration_id_14286d876e86361c_fk_sentry_integration_id" IMMEDIATE; ALTER TABLE "sentry_alertruletriggeraction" DROP CONSTRAINT "sentry_integration_id_14286d876e86361c_fk_sentry_integration_id"
  4. COMMIT

所以現(xiàn)在我們部署它并進(jìn)入下一階段。

下一階段涉及從代碼庫(kù)中刪除對(duì)模型的所有引用。所以我們這樣做,然后我們生成一個(gè)遷移,從遷移狀態(tài)中刪除模型,而不是數(shù)據(jù)庫(kù)。此遷移中的操作如下所示

  1. operations = [ 
  2.         migrations.SeparateDatabaseAndState( 
  3.             state_operations=[migrations.DeleteModel(name="AlertRuleTriggerAction")], 
  4.             database_operations=[], 
  5.         ) 
  6.     ] 

并且生成的 SQL 顯示沒(méi)有發(fā)生數(shù)據(jù)庫(kù)更改。所以現(xiàn)在我們部署它并進(jìn)入最后一步。

在這最后一步中,我們只想手動(dòng)編寫(xiě) DDL 來(lái)刪除表。所以我們使用 sentry django makemigrations --empty 來(lái)產(chǎn)生一個(gè)空的遷移,然后修改操作如下:

  1. operations = [ 
  2.         migrations.RunSQL( 
  3.             ""
  4.             DROP TABLE "sentry_alertruletriggeraction"
  5.             """, 
  6.             reverse_sql="CREATE TABLE sentry_alertruletriggeraction (fake_col int)", # We just create a fake table here so that the DROP will work if we roll back the migration. 
  7.         ) 
  8.     ] 

然后我們部署它,我們就完成了。

外鍵

創(chuàng)建外鍵大多沒(méi)問(wèn)題,但是對(duì)于像 Project、Group 這樣的大/繁忙的表,由于獲取鎖的困難,它可能會(huì)導(dǎo)致問(wèn)題。您仍然可以創(chuàng)建 Django 級(jí)別的外鍵,而無(wú)需創(chuàng)建數(shù)據(jù)庫(kù)約束。為此,請(qǐng)?jiān)诙x鍵時(shí)設(shè)置 db_constraint=False。

重命名表

重命名表很危險(xiǎn),會(huì)導(dǎo)致停機(jī)。發(fā)生這種情況的原因是在部署期間將運(yùn)行舊/新代碼的混合。因此,一旦我們?cè)?Postgres 中重命名該表,如果舊代碼嘗試訪問(wèn)它,它就會(huì)立即開(kāi)始出錯(cuò)。有兩種方法可以處理重命名表:

  • 不要在 Postgres 中重命名表。相反,只需在 Django 中重命名模型,并確保將 Meta.db_table 設(shè)置為當(dāng)前表名,這樣不會(huì)有任何中斷。這是首選方法。
  • 如果你真的想重命名表,那么步驟將是:
  • 使用新名稱(chēng)創(chuàng)建一個(gè)表
  • 開(kāi)始對(duì)舊表和新表進(jìn)行雙重寫(xiě)入,最好是在事務(wù)中。
  • 將舊行回填到新表中。
  • 將 model 更改為從新表開(kāi)始讀取。
  • 停止寫(xiě)入舊表并從代碼中刪除引用。
  • 丟棄舊表。
  • 一般來(lái)說(shuō),這是不值得做的,與回報(bào)相比,這需要冒很多風(fēng)險(xiǎn)/付出很多努力。

添加列

創(chuàng)建新列時(shí),它們應(yīng)始終創(chuàng)建為可為空的。這是出于兩個(gè)原因:

  • 如果存在現(xiàn)有行,添加非空列需要設(shè)置默認(rèn)值,添加默認(rèn)值需要完全重寫(xiě)表。這是危險(xiǎn)的,很可能會(huì)導(dǎo)致停機(jī)
  • 在部署期間,新舊代碼混合運(yùn)行。如果舊代碼嘗試向表中插入一行,則插入將失敗,因?yàn)榕f代碼不知道新列存在,因此無(wú)法為該列提供值。

向列添加 NOT NULL

將 not null 添加到列可能很危險(xiǎn),即使該列的表的每一行都有數(shù)據(jù)。這是因?yàn)?Postgres 仍然需要對(duì)所有行執(zhí)行非空檢查,然后才能添加約束。在小表上這可能沒(méi)問(wèn)題,因?yàn)闄z查會(huì)很快,但在大表上這可能會(huì)導(dǎo)致停機(jī)。這里有幾個(gè)選項(xiàng)可以確保安全:

  • ALTER TABLE tbl ADD CONSTRAINT cnstr CHECK (col IS NOT NULL) NOT VALID; ALTER TABLE tbl VALIDATE CONSTRAINT cnstr;. 首先,我們將約束創(chuàng)建為無(wú)效。然后我們之后驗(yàn)證它。我們?nèi)匀恍枰獟呙枵麄€(gè)表來(lái)驗(yàn)證,但我們只需要持有一個(gè) SHARE UPDATE EXCLUSIVE 鎖,它只會(huì)阻止其他 ALTER TABLE 命令,但允許讀/寫(xiě)繼續(xù)。這很有效,但會(huì)有 0.5-1% 的輕微性能損失。在 Postgres 12 之后,我們可以擴(kuò)展這個(gè)方法來(lái)添加一個(gè)真正的 NOT NULL 約束。
  • 如果表足夠小并且體積足夠小,那么創(chuàng)建一個(gè)普通的 NOT NULL 約束應(yīng)該是安全的。小是幾百萬(wàn)行或更少。

添加具有默認(rèn)值的列

向現(xiàn)有表添加具有默認(rèn)值的列是危險(xiǎn)的。這需要 Postgres 鎖定表并重寫(xiě)它。相反,更好的選擇是:

在 Postgres 中添加沒(méi)有默認(rèn)值的列,但在 Django 中添加默認(rèn)值。這使我們能夠確保所有新行都具有默認(rèn)值。這是通過(guò)修改遷移文件以包含 migrations.SeperateDatabaseAndState 來(lái)完成的

  1. operations = [ 
  2.     migrations.SeparateDatabaseAndState( 
  3.         database_operations=[ 
  4.             migrations.AddField( 
  5.                 model_name="mymodel"
  6.                 name="new_field"
  7.                 # Don't use a default in Postgres, a data migration can be used afterward to backfill 
  8.                 field=models.PositiveSmallIntegerField(null=True), 
  9.             ), 
  10.         ], 
  11.         state_operations=[ 
  12.             migrations.AddField( 
  13.                 model_name="mymodel"
  14.                 name="new_field"
  15.                 # Use the default in Django, new rows will use the specified default 
  16.                 field=models.PositiveSmallIntegerField(null=Truedefault=1), 
  17.             ), 
  18.         ], 
  19.     ) 
  20.     ] 
  • 通過(guò)數(shù)據(jù)遷移使用默認(rèn)值回填預(yù)先存在的行。

改變列類(lèi)型

改變列的類(lèi)型通常是危險(xiǎn)的,因?yàn)樗枰貙?xiě)整個(gè)表。有一些例外:

  • 將 varchar() 更改為更大尺寸的 varchar。
  • 將任何 varchar 更改為 text
  • 將 numeric 更改為 numeric,其中 precision 更高但 scale 相同。

對(duì)于任何其他類(lèi)型,最好的前進(jìn)路徑通常是:

  • 創(chuàng)建具有新類(lèi)型的列。
  • 開(kāi)始對(duì)新舊列進(jìn)行雙重寫(xiě)入。
  • 回填并將舊列值轉(zhuǎn)換為新列。
  • 更改代碼以使用新字段。
  • 停止寫(xiě)入舊列并從代碼中刪除引用。
  • 從數(shù)據(jù)庫(kù)中刪除舊列。
  • 通常,這值得在 #discuss-backend 中討論。

重命名列

重命名列是危險(xiǎn)的,會(huì)導(dǎo)致停機(jī)。發(fā)生這種情況的原因是在部署期間將運(yùn)行舊/新代碼的混合。因此,一旦我們?cè)?Postgres 中重命名該列,如果舊代碼嘗試訪問(wèn)它,它就會(huì)立即開(kāi)始出錯(cuò)。有兩種方法可以處理重命名列:

  • 不要重命名 Postgres 中的列。相反,只需在 Django 中重命名字段,并在定義中使用 db_column 將其設(shè)置為現(xiàn)有的列名,這樣就不會(huì)中斷。這是首選方法。
  • 如果你真的想重命名列,那么步驟將是:
    • 創(chuàng)建具有新名稱(chēng)的列
    • 開(kāi)始對(duì)新舊列進(jìn)行雙重寫(xiě)入。
    • 將舊列值回填到新列中。
    • 將字段更改為從新列開(kāi)始讀取。
    • 停止寫(xiě)入舊列并從代碼中刪除引用。
    • 從數(shù)據(jù)庫(kù)中刪除舊列。

一般來(lái)說(shuō),這是不值得做的,與回報(bào)相比,這需要冒很多風(fēng)險(xiǎn)/付出很多努力。

 

責(zé)任編輯:武曉燕 來(lái)源: 黑客下午茶
相關(guān)推薦

2022-01-11 20:42:54

開(kāi)發(fā)Sentry標(biāo)志

2022-01-17 19:34:43

SentryWeb APISentry API

2022-01-18 23:26:45

開(kāi)發(fā)

2022-01-15 23:33:47

SentryPyCharm配置

2022-01-02 23:26:08

開(kāi)發(fā)SDK Sentry

2022-01-03 22:59:30

開(kāi)發(fā)SDK數(shù)據(jù)

2021-12-15 20:06:48

ReactJSSentry開(kāi)發(fā)者

2021-12-25 22:31:55

Sentry 監(jiān)控SDK 開(kāi)發(fā) 性能監(jiān)控

2022-01-21 21:33:03

開(kāi)發(fā)JavaScript應(yīng)用

2022-01-13 20:13:31

元宇宙搜索引擎

2021-12-31 18:35:40

監(jiān)控Sentry開(kāi)發(fā)

2022-01-02 06:59:43

SentrySDK 開(kāi)發(fā)客戶端報(bào)告

2021-12-16 20:12:37

后端開(kāi)發(fā)Sentry

2022-01-19 19:49:53

Sentry瀏覽器SDK

2022-01-20 19:49:10

Sentry開(kāi)發(fā)Scope

2021-12-17 19:15:51

前端蟲(chóng)洞狀態(tài)

2017-04-01 18:00:08

開(kāi)發(fā)者數(shù)據(jù)庫(kù)

2011-03-16 09:38:05

2011-03-16 09:33:45

數(shù)據(jù)庫(kù)開(kāi)發(fā)錯(cuò)誤

2017-11-23 15:06:14

前端數(shù)據(jù)庫(kù)開(kāi)發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)