モヒカンメモ

髪色が定期的に変わることに定評のある(比較的)若者Webエンジニアの備忘録

DBマイグレーションツールのロールバック機能は使うな

データベースマイグレーションツールのロールバック機能は安全に使えないので使うべきではないと思う。

ロールバック機能

RDBMSのデータベーススキーマを管理するためのツールとして flyway や、ウェブアプリケーションフレームワーク組み込みのマイグレーションツール (例: Laravel Migration ) がある。

DBマイグレーションツールにはマイグレーションを進める (up) 機能のほかに、進めた変更をロールバックする (down) 機能がついている。

マイグレーションを進める例:

CREATE TABLE customers (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  email VARCHAR(100)
);

マイグレーションをロールバックする例:

DROP TABLE customers;

この記事では、ロールバックする (down) 機能に焦点を当てて話す。

DBマイグレーションは失敗し得る

ご存知の通り、DBマイグレーションは失敗し得る。

  • マイグレーションに複数のDDLが含まれていて、一部だけが失敗した
  • 各種制約 (ユニーク制約、外部キー制約、チェック制約など) に反するデータを一時的にでも作成、変更、または削除しようとした
  • テーブルに変更を加えるのに必要なメタデータロックを獲得できず、タイムアウトした
  • etc...

さて、あなたがこれまで書いてきたロールバック処理はこのうちのどれを想定したものだろうか?

マイグレーション失敗の原因に応じてロールバック方法が異なる

言いたいことはこの一言に尽きる。

当たり前の話として、予想される失敗に応じてrollbackを書くべきで、失敗が予想されるなら事前にテスト環境や検証環境などで検証を行うことで失敗する確率は減らせる。 自分はリスクが高いと感じるスキーマ変更を行うときは本番DBのスナップショットから検証用DBを立ち上げ、マイグレーションを適用し、正常に完了することや変更にかかる時間を計測している。

そこまでしても失敗するときは失敗する。 サービス規模によって本番と同等の検証用DBを用意することが現実的でないこともあるし、負荷がかかってないと発現しないトラブルもある (読み書き頻度が高する or long txが居てメタデータロックが取れないとか)。

失敗するまでテーブル構造やデータがどういう状態か確定しないので、どのようなロールバックを行うのが適切かは失敗するその時まで分からない。 なので、マイグレーションを書く時点では安全な (= 絶対に成功する) ロールバック処理を書くことはできない。故にロールバック機能を使うべきではない。

ロールバックも前進 (up) させればよい

ロールバック機能を使わないとしたらどうすれば良いのか?

知っている人には当たり前の話だが、あえて丁寧に説明しておくとデータベースのマイグレーションが失敗するとサービスが止まる。可能な限り早急にロールバックしてサービスを復旧させたいだろうが、なぜ失敗したのかをちゃんと確認しよう。必要に応じて関係者にメンションを飛ばす。事件事故の報告は早ければ早いほど良い。一人では冷静に対処出来ないなら誰かに助けを求めてペアオペするのも有効。

失敗の原因が分かったら安全にロールバックする、あるいは理想状態に持っていくための新しいマイグレーションを用意する。DDL/DSLを書いてcommitしてPull Requestを上げてレビューなどの正規のリリースプロセスを経て再度マイグレーションを行う。

緊急性が高い場合は本番データベースで直接オペレーションすることもあるだろうが、そのときは絶対に一人でやらない方がいい。第三者にレビューしてもらったりペアオペにすることで的はずれな対応をしている場合に気づける確率が上がる。的はずれな対応をして二次被害を生むことが最悪なので、逸る気持ちを押さえながらそれを回避することを一番に考える。