そのPostgresマイグレーションは本当に安全か?
Is your Postgres migration safe or not safe?
Postgresのマイグレーションが本番環境でロックやテーブル書き換えを引き起こさないかを判定するツール「safe-not-safe」が登場。migration.sqlを解析し、add-column-constant-defaultやcreate-index-concurrently、validate-constraintといった各文が安全かどうかを、libpg_query 17(wasm)を使って1文ずつチェックする。起動時のリスクパターンに合致しなければSAFEと表示する仕組みだ。
SAFE— No blocking pattern found. The checked statements avoid the common lock, rewrite, and rollout traps in the launch rule set.
HNでの議論
19- orf
こうしたルールベースのマイグレーション安全性チェックはシンプルだが、とても完全とは言えない。
問題は、マイグレーションの安全性の一部がデータベースの状態に依存しており、それがDDL文だけでは表現されないことだ。たとえば、カラムの型を変更する場合、元のカラムの型によって、何もしないで済む場合もあれば、排他ロックを伴うテーブル全体の書き換えが必要になる場合もある。
他にも、変更しようとしているカラムが外部キーの場合、複数のテーブルがロックされる可能性があるといった落とし穴がある。
数年前に私は深みにはまり、与えられたマイグレーションを実際のスキーマに対してイントロスペクトし、Postgresに実際に何をしているのかを教えてもらうシステム[1]を作った[2]。
こうした機能がもっと組み込みでサポートされると素晴らしいのだが(DDL文に対するEXPLAIN?)、この方向性は静的なルールセットよりも安全で正確に感じられる。
安全性は、変更されるテーブルのサイズやアクティビティにも依存する(つまり、空のテーブルを書き換えるのは問題ない)。データベースが実行するロックとアクションを正確に表現できれば、本番環境のメトリクスと統合して、データベース群全体にわたる実際の安全性を推測ではなく判断できるようになる。
1. https://github.com/orf/locksmith
2. https://github.com/orf/locksmith/blob/f8798c6ee92bfae10d416c...
- fabianlindfors
こうしたマイグレーションリンターは有用ではあるが、安心感を与えるには十分ではないと思う。私はここ数年、自分自身の足を撃ち抜くあらゆる方法をカバーしようとするゼロダウンタイムのスキーママイグレーションツールをメンテナンスしてきた:https://github.com/fabianlindfors/reshape
これはマイグレーションがデータベースをロックしないことを保証するが、おそらくもっと重要なのは、デプロイ中に古いスキーマと新しいスキーマの両方をサポートし、それらの間で自動的にデータを移行することで、アプリケーションのゼロダウンタイムロールアウトも可能にすることだ。また、標準的なSQLコマンドを使う場合には通常複数の別々のデプロイが必要となるバックフィルなども処理する。
- nijave
Ruby向けには https://github.com/ankane/strong_migrations もある。
チェックや説明はかなりシンプルでわかりやすいので、このライブラリを使っているかどうかに関わらず、良いリファレンスにもなる。