Django migrationをオンラインで行えるのかどうか考えていた。
オンラインで行えるのかどうかはDjangoのmigrationコマンドの問題ではなく、使っているDB(今回の場合だとPostgreSQL)がどのようにロックを行うのかによるということがわかった。
では具体的にどうすれば良いのかを調べてみたのでメモ。(未検証なので注意。)
参考)
PostgreSQLで安全にテーブル定義を変更する - LCL Engineers' Blog
どうなるとダウンタイムが発生してしまう?
ALTER TABLEを実行した対象テーブルが排他ロック(参照も更新もできない)を取って、かつ完了までに長時間かかってしまう場合に、そのテーブルを参照・更新するリクエストが返らなくなってしまう。
PostgreSQLの場合、
カラム追加(Default制約なし)やカラム削除などは一瞬で終わるらしい。
一瞬で完了するなら排他ロックをとっても特に問題ない。(デッドロックには注意)
問題は、どうしても時間がかかってしまう変更(not null追加など)
どうすればいいか?
mysqlならオンラインでAlterできる仕組みが5.6以降あるらしい。
仕組みとしては、
- 内部で別途、変更後構造のテーブルを構築
- 変更前テーブルから変更後テーブルへデータをコピー。トリガーなどを使って変更前テーブルへの更新は変更後テーブルへも適用されるようになっており、データが常に同期された状態になる。
- データ同期が完了した時点でテーブルを入れ替える
PostgreSQLにはこの仕組はない。
独自に同じことをすればよさそう?
(※pg_repackをつかえば自動で行えるかも?)
- 変更後構造のテーブルを新規追加
- データコピーとトリガーを使って変更前テーブルと変更後テーブルのデータ内容を同期
- 同期が完了したタイミングでテーブルを入れ替え。