inSmartBank

B/43を運営する株式会社スマートバンクのメンバーによるブログです

Kaigi on Rails 2023 『32個のPRでリリースした依存度の高いコアなモデルの安全な弄り方』 で話しきれなかったもの

10月27日~28日に開催されたKaigi on Rails 2023の2日目に『32個のPRでリリースした依存度の高いコアなモデルの安全な弄り方』という発表をさせていただきました。実は発表前日までリハーサルを行なっておらず、30分枠だったのですが1時間くらいかかる巨大資料が出来上がってしまいました…

今回の発表ではオンラインDDLについて色々と調べながら資料を作ったので、このままお蔵入りさせてしまうのも勿体なく、このブログで削ってしまった部分を供養したいと思います。また、Xでいただいたコメントへの回答も載せています!

本編を簡潔にまとめると

  • 1年前にB/43で一番READ/WRITEが多いテーブルの定義変更をした話を紹介
  • オンラインでテーブル定義変更するために抑えるべき箇所について紹介
    • オンラインDDLが適用される範囲と落とし穴について
    • テーブル定義とアプリケーションの定義が不一致になるタイミングについて
  • 実際のプロジェクトで採用したリリース手順を紹介

発表本編で使用した資料はこちらになりますので、内容が気になる方はぜひチェックしてみてください。

speakerdeck.com

削ってしまった話

オンラインDDLの注意点 一貫性読み取りエラーについて

MySQLのトランザクション分離レベルをREPEATABLE READにしている場合、あるトランザクションとオンラインDDLがバッティングしてしまうと「Table definition has changed, please retry transaction」というエラーが発生してしまいます。

このエラーが発生する状況は以下のように、あるトランザクションが開始され、そのトランザクションでテーブルBに対してSELECTを行う前に、オンラインDDLでテーブルBの定義が変更されたケースです。

REPEATABLE READでは、トランザクションの最初にテーブルへアクセスした時点でDBのスナップショットが作成されます。トランザクション中に実行されるDMLはすべてそのスナップショットに対して行われ、コミットした時にスナップショットへの内容がDBに反映されます。

このスナップショットが作成された後に、トランザクション中にアクセスするテーブルの定義が変更されてしまうと、スナップショットのテーブル定義と不一致となってしまうため上記のエラーが発生します。

このエラーはトランザクションの実行時間が短かったとしても、オンラインDDL側とタイミングが合ってしまえば発生しうるエラーです。そのため、オンラインDDLの中でこのエラーを完全に回避する方法をまだ見つけられておらず、どうしても回避したい場合はpt-online-schema-change等のツールを使って、オンラインDDLではない方法を取る方が良さそうです。(もし知っている人がいたら教えてください)

このエラーが発生する条件はMySQLのバージョンによっても変わるようなので、こちらの記事も併せてご覧ください。

zenn.dev

ALGORITHM=INSTANT

MySQL 8.0.12からALGORITHMにINSTANTが追加されました。このALGORITHMは、DDLの実行時にメタデータのみを更新し、テーブルデータは影響を受けないため高速に実行することができます。

非常に便利な機能なのですが、サポートされているDDL操作はまだ一部となっています。

  • インデックスタイプの変更
  • カラムの追加
  • カラムのデフォルト値の設定/削除
  • ENUM または SET カラムの定義の変更
  • VIRTUAL カラムの追加/削除
  • テーブル名の変更

またカラムの追加においても、INSTANTの対象外のDDLと組み合わせて実行するケースや、カラム位置を指定しての追加ではINSTANTでは無くなってしまうので注意が必要です。

そのため、例えば以下のように change_tablebulk: trueを指定して実行する場合、INSTANTの対象外のDDLが混ざってしまうと誤動作となってしまうので注意が必要です。

ちなみにB/43ではカラムを追加する時には必ず位置を指定しています。ここら辺の規約は各社さんそれぞれだと思うのですが、「ペアプロしようぜ 〜3人で登壇!? 楽しくて速いペアプロ/モブプロ開発〜」の発表でフィヨルドブートキャンプさんのコードを見た時に位置指定をされていないようだったので「おっ!」となりました。

③ strong_migrations

言わずと知れたgemかと思いますが、B/43でもstrong_migrationsを入れて危険な操作を行おうとした時に事前に気付けるようにしています。

例えば以下のようにカラムを削除する変更を行おうとした際、

下のようにエラーを吐いて修正方法を教えてくれるため、DDLに明るくない人が変更しようとした時に事前に気づくことができます。

以上が本編から時間の都合で削ってしまった内容の紹介でした。

Xでもらった反響への返信

当日お返しできなかったので、こちらで回答したいと思います!

B/43だとdb:rollbackが必要となるケースがあれば、Airflowというワークフローの仕組みの中でECSを立ち上げて任意のrailsコマンドを実行できるため、それを経由して行うと思います。ただ、これまでdb:rollbackが必要なケースには遭遇してません。もし戻せない場合は、新しいマイグレーションファイルを準備することになるかと思います。

深夜に長期メンテを行う場合には、VISA側で決済を拒否するメンテナンスモードがあるため、そちらを利用するケースもあったりします。ただユーザーから見るとなぜ決済が失敗したのか、店頭では分からないので不便をかけることになってしまい、できるだけメンテナンスモードを避けたいというのがあります。

登壇した感想

Kaigi on Railsは今回で3回目の登壇となったのですが、過去2回との違いや改めて感じたオフライン開催の良さについては個人ブログの方に書いたのでよければご覧ください。好評だったSmartBankのスライド作成術についても軽く触れています。

shohei1913.hatenablog.com

お礼

本発表を聞いてくださった皆様、Kaigi中に感想を伝えにきてくださった方々、参加ブログ等で感想を書いてくださった方々、ありがとうございました 🙌 

オンラインDDLについては、みんな知ってるけど細かい挙動に不安があったり、規模が大きくなるほどオンラインDDLに頼れない場面も出てきたりと色々な悩みだったり感想を聞くことができて発表した甲斐があったなと思いました。

そしてKaigi on Railsを運営し続けてくださっているオーガナイザーの皆様に改めて感謝を伝えさせていただくとともに、来年の開催も楽しみにしております!

We create the new normal of easy budgeting, easy banking, and easy living.
In this blog, engineers, product managers, designers, business development, legal, CS, and other members will share their insights.