Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Railsのマイグレーション、どこまで安全にできるか

Manami Nakamura
August 24, 2023
10

 Railsのマイグレーション、どこまで安全にできるか

Gotanda.rb#54 にてお話しした資料です。
https://gotanda-rb.connpass.com/event/291206/

Manami Nakamura

August 24, 2023
Tweet

Transcript

  1. 自己紹介 中村 愛美 (@mnmandahalf) 経歴 SE(2年) 株式会社リブセンス(5年半) 株式会社primeNumber(3ヶ月)← 現職 お仕事

    ソフトウェアエンジニアとして、データ分析基盤の総合支援サービス trocco® を作っています 趣味 旅行✈、珈琲☕、ベルーガ🐬 コアラ🐨 マーモット🐭の動画を見る 今日はRails × MySQLの話をします (PostgreSQLユーザーのみなさん、雰囲気を感じ取っていただけると嬉しいです)
  2. オンラインDDLでも、ALGORITHM=INSTANTとINPLACEがあるよね? • INSTANTとは → メタデータの変更しかしないので、DDLの適用が一瞬 • MySQL 8.0.12から導入された • INPLACEはINSTANTよりは時間がかかるので、以下のようなリスクがある

    ◦ レプリケーション遅延( Auroraの場合は少ないらしい) ◦ メモリの逼迫 ◦ 例えば数分かかるインデックス追加 DDLが後述のメタデータロック待ちのタイムアウトで失敗する可 能性がある。リリースフローにマイグレーションを含めている場合、なかなかマイグレーションが終 わらずリリースに影響が出ることも。 ◦ 例:セカンダリインデックスの追加・削除、位置指定してのカラム追加(〜 8.0.28) • 少ないですがALGORITHM=COPYで読み書き同時DML許可もあるようです
  3. INSTANT DDL以外は怖いので禁止したい! • ALGORITHM=INSTANT を強制してみる • どんな時にワークする? ◦ とりあえずエラーにして、通常のマイグレーションフローから分離する ◦

    カラムの追加は許可するが、位置の指定は禁止したい • (余談)インデックスの追加限定で、 add_index ヘルパーに index_algorithm オプションを発見 ◦ https://github.com/rails/rails/commit/e199dc1a570d4f0d9a07628268835bce5aab2732 ◦ 元々PostgreSQLのインデックス追加の際にテーブルロックを不要にするアルゴリズムを指定可能にしたときに、 MySQLのぶんもついでに追加 されたようだった
  4. 実装編 • 最終的に実行されるSQLの末尾にオプションを付与したい • MySQLの場合、 ActiveRecord::ConnectionAdapters::MySQL::DatabaseStatement#executeの引数に 最終的なSQLが渡される • ActiveRecord::ConnectionAdapters::Mysql2Adapterで、executeメソッドをオーバーライ ドしたモジュールをprependする

    • ただし、マイグレーション時のSQLだけ上書きしたい • 実はもうありました:https://github.com/anthonyalberto/mysql_online_migrations • ちなみに、Ridgepoleには --alter-extra オプションがある https://github.com/ridgepole/ridgepole#add-extra-statement-to-alter
  5. Railsでメタデータロック待ちリスクを回避する • execute(“SET SESSION lock_wait_timeout = 5;”) のようにすればいいが... • お悩みポイント

    ◦ マイグレーションファイルの changeに書くとロールバックできない ◦ 毎回指定するの忘れそう ◦ マイグレーション失敗の確率が高まるし、ちょっと時間おいて自動リトライできないかな?
  6. 結論 • オフラインDDLの実行時チェック • 非 INSTANT DDLの実行時チェック • メタデータロック待ち対策 •

    メタデータロック獲得タイムアウトでDDLが失敗した場合のリカバリ ここまではRails標準マイグレーションのフローでもできそう! という実験でした