hacomono TECH BLOG

フィットネスクラブ・スクールなど施設・店舗のための会員管理・予約・決済システム「hacomono」 開発チームの技術ブログ

急成長スタートアップで経験したスキーマ変更の壁

こちらの記事はhacomono Advent Calendar 2023の23日目の記事です

こんにちは、hacomonoでプロダクト開発をしております田中です!

最近は子供の保育園が始まり毎朝バタバタしていますが、hacomonoはフルフレックス制度を導入しているため、始業時間を柔軟に調整できるので助かっています。

hacomonoに入社して2年と10ヶ月目になりましたが、この数年で社員の数も約30人前後から200人を超えるまでに増え、プロダクトも加速度的に大きくなり、開発をする上でさまざまな障壁に直面してきました。

hacomonoは、24時間運営をしているお客様にも多くご利用いただいているため、頻繁にメンテナンスタイムを設けることが難しく、ダウンタイム無しでプロダクトをアップデートし続けることが適宜求められます。

今回は過去経験した中でも特に障壁に感じていた事の1つであるDBのスキーマ変更について、入社直後から現在までに直面した問題を経験ベースで書いていきたいと思います。

DDL、データ移行に時間がかかるようになる

hacomono入社後の約3ヶ月後、新機能のリリースでスキーマ変更がタイムアウトしている事象が起きていました。自身が開発していたものではなかったので当時は原因をあまり理解できていませんでしたが、DDL先のレコード量が多い状態でテーブルコピーが発生し、Railsのmigrationが途中でタイムアウトしてしまうような問題が起きていました。

SQL自体はタイムアウトしていましたが、Railsのmigraionのステータスを管理しているテーブル上のステータスが完了状態になっていたため、恒久対応としてDDLが失敗した環境に対して手動でSQLを流したことを今でも覚えています。

顧客によっては膨大なデータ量になっていることを当時は改めて実感しました。

DDL中に排他ロックがかかる

hacomono入社後の約1年半後、自身が開発していた新機能のリリースが近くなってきたこともあり、スキーマ変更の事前テストを行っていました。前述していたDDLのタイムアウトを経験していたのでデータ量の多い検証環境を作成し、そこに対して本番で想定しているDDLを実行しつつ画面を触りながら各トランザクションを走らせて検証を行いました。

すると、DDL対象のテーブルでロック待ちが発生し、特定画面の操作でサーバーエラーが発生することがわかりました。

当時のDBはMySQL5.7をメインで利用していたため、MySQL5.7のドキュメントを見つつ原因が判明しました。この時の問題は、外部キーのカラムを追加しようとしていたため、DDL対象のテーブルに排他ロックがかかり、並列で走るDML(INSERTやUPDATEなど)が不可になるような状態になっていることがわかりました。

MySQLのドキュメントを漁りつつ、社内の有識者にも相談し、foreign_key_checksを一時的にOFFにしながらALTER TABLEを行うことでオンラインDDLで実行できることがわかったため、SQLを調整して再検証を行いました。オンラインDDLで実行することで並列のDMLが許可されるようになったため、本番リリースもこの方式でいくことにし、リリース日を迎えました。

リリース日当日はテーブルをロックすることはなくなったのですが、ユニーク制約にひっかかってしまうDMLのクエリが多く走っており、結局深夜までDDLが通らずに苦い思い出となりました。

ただ、事前に検証をしっかり行ったことで大事故にはならずにリリースを終えることができたのはとても良い経験になりました。

以下の記事でより詳細な当時の対応を書いていますので是非見ていただければと思います!

MySQL 5.7のオンラインDDLによるサービス無停止のカラム追加 - hacomono TECH BLOG

必須カラムの存在によって切り戻しできない

直近約1年程はモノリスなコードの肥大化に伴いインシデントの量も増加し、リリースのPRをRevertするような場面が多々発生しました。アプリケーションコードのRevertに関しては比較的容易ですが、DBを戻すのは一筋縄ではいきません。

基本的にはアプリケーションのコードよりも先にスキーマ変更だけ実施しておき、後からコードをリリースするようなやり方でリリースしていましたが、新機能で利用する必須のカラムがある場合などは、データ移行を行ったり、アプリケーションコードと同時にリリースする時もありました。

しかし、必須カラムの追加を行ってしまうとリリースの切り戻しの難易度があがります。必須カラム追加後にアプリケーションコードを切り戻してしまうと、古いコードでは該当テーブルに対して意図せぬデフォルト値での保存になってしまう場合があります。

こういった問題が多く発生していたため、リリース前にスキーマ変更だけを行った状態でrspecが全て通ることを確認してからリリース判定を行うような運用になりました。

組織が大きくなると様々なチームからスキーマ変更が実施されるため、スピードはなるべく落とさず、より安全面を意識するような運用に変わってきたなと実感しました。

オンラインDDLでもスキーマ変更ができない

ここ半年は顧客のデータ量増加が顕著になり、常にトランザクションが途切れないため、日中のスキーマ変更が難しくなってきました。今まではオンラインDDLで実行すれば問題なく実施できていましたが、トランザクションの数が増えてきたことで、DDL実行開始時と終了時にメタデータロックを獲得できず、他トランザクションを含めて待機状態になってしまうような傾向がでてきました。

日中のDDL実行が難しくなってきたため、交代制で深夜にDDLを実施するような運用に変わりましたが、深夜でさえ中々1発でDDLが通らない時もあります。

メンテナンスタイム以外の時間で安全にスキーマ変更を行う必要がある場合は、今時点ではこの方式に着地しています。

まとめ

スタートアップにいると前例が役に立たず常に新しい運用方法を模索しないといけない場面が多く、試行錯誤の繰り返しだなと思うことが多々ありますが、こういった経験は本で読むだけでは体得できないモノだと思います。

苦しい場面もありますが、とても貴重な経験でありエンジニアとしての成長を実感できています。


株式会社hacomonoでは一緒に働く仲間を募集しています!
採用情報や採用ウィッシュリストも是非ご覧ください!