hacomono TECH BLOG

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

DBスキーマ変更でのMetadata lock自動検知+リトライやってみました。2024/03版

運用保守部のよこちゃん (@jikun) です。

最近、平日に長めのお休みを頂いて息子の小学校卒業記念として家族でUSJに行ってきました。

アトラクションの待ち時間についついSlack見てしまいましたが、みなさんが温かくサポートして仕事を進めてくれており本当に休みやすい環境に感謝しました!

最終日は、USJ近くのホテルからあべのハルカス、道頓堀あたりを5時間ほどブラブラ探索しながら伊丹空港へ移動しましたが、この写真のようにお土産含めて家族全員分の荷物を1人で持つスタイルで頑張りました。

日々の運用保守業務で鍛えているパワー💪 をプライベートでも存分に発揮してまいりました。


Metadata lockとの闘い 2024/03 ver

hacomonoはプロダクトが急成長していますと言って既に2-3年経っている気がしますが、
今も継続して急成長中です!

コードが増えるのはもちろんDBのテーブルやカラムも増えます。
そうなると問題となるのが、スキーマ変更でのMetadata lock取得待ちです。
この辺りの詳細は、スクール機能開発のプリンス たなしゅんの記事をご参考にしてください。 techblog.hacomono.jp

前提とここまでの流れ

  • hacomonoはバックエンドでRailsを使っており、DBスキーマ変更もActive Recordのmigration機能を使っております。(DBは環境によってRDS、Autora serverless v2が混在しておりMySQL Ver8系です)
  • DBスキーマ変更はリリースタイミングで実行していましたが、徐々にオンライン DDL が Metadata lock をすぐに取れないことによるサービス影響が無視出来なくなってきました。
  • テナント(顧客)単位でDBを分割しているので、対策として大量レコードを持つテナントは深夜にMetadata lock 取得待ちを監視しながら手動でDBスキーマ変更しはじめました(深夜作業大好きな私も頑張ってます♪ )→こちらは完全自動化準備中です
  • とはいえ5,000以上テナントがあるため深夜にMetadata lock取得待ちを監視しながらやりきるのが難しいです。
  • そのため日中リリースタイミングで実行するmigrationについては自動でMetadata lock 取得待ちを監視して検知後、MySQL内のDDLプロセスをKillしてActive Recordのmigrationをリトライする仕組みを作成しました
  • 検知するとこんな感じで通知がきます

この仕組みは以下の2つのスクリプトから構成されています

  1. メインスクリプト
  2. Metadata lock取得待ち監視スクリプト

簡単な処理の流れ

  1. メインスクリプトがMetadata lock取得待ち監視スクリプトをバックグランド起動
  2. メインスクリプトがActive Recordのmigrationを実行
  3. Metadata lock取得待ち監視スクリプトがMySQLへ接続し一定間隔で以下のSELECT文にて監視

     SELECT id, db, state, info FROM INFORMATION_SCHEMA.PROCESSLIST WHERE state LIKE '%Waiting for table metadata lock%'
    
  4. Metadata lock取得待ちは発生してもすぐに解消されることが多く、その場合サービス影響が出ることはほぼありません。そのため検知しても一定回数は見逃します
  5. Metadata lock取得待ちの検知回数がしきい値を超えた場合、ログにエラーメッセージを記載して元のDDL文のMySQLプロセスをkillします。
  6. メインスクリプトは一定間隔でログファイルを監視し、Metadata lock 取得待ち起因のエラーメッセージを検知した場合、Acrive Recordのmigrationをリトライさせます
  7. Acrive Recordのmigrationがリトライ回数を超えた場合、もしくは全体実行時間のしきい値を超えた場合、何らかの異常があると判断し全処理を停止させSlack通知させます。

メインスクリプトのコードを一部抜粋。Metadata lock取得待ち監視の方は秘伝のタレが色々詰まっているのでまたの機会にさせて頂きます。

while $CONTINUE; do
  echo 'START bin/rake db:migrate'
  #
  # db:migrate を実行
  #
  check_mlm_process
  bin/rake db:migrate 2>&1 | tee $MIGRATE_LOG_FOR_CHECK
  MIGRATE_STATUS=${PIPESTATUS[0]}

  if [[ "$MIGRATE_STATUS" = "0" ]]; then
    # db:migrate が成功したらループを抜ける
    CONTINUE=false
  else
    if grep 'DDL STOPPED WAITING FOR METADATA LOCK' $MIGRATE_LOG_FOR_CHECK > /dev/null; then
      # db:migrate が失敗し process kill した旨のログが出力されていたらリトライ
      echo 'Killed by metadata lock! retry db:migrate'
      CONTINUE=true
    else
      # それ以外のエラーは、今まで通り失敗させる
      echo 'Migration error occurred!'
      exit 1
    fi
  fi
done

開発チーム全員に協力してもらってオンライン DDL は必ず冪等になるように書かれており
migration失敗時にも最初からリトライ可能にしております。

2本のスクリプトそれぞれが想定外の終了をしないようにかなり気を使いました。

あたかも私が作りましたの体で書きましたがこの仕組みを作ってくれたのはテックリードのいわざーさんです。
いつも欲しいものをサクっと作ってくれて感謝です。

最後に

今回はリリースにおける品質改善の一環としてDBスキーマ変更の影響を最小限にする施策を紹介しました。

その他にも、社内外の問い合わせ対応をしながら、社内の生産性向上のための機能開発や、データエクスポート機能の非同期化などパフォーマンス改善含めて幅広く対応しています。

そして2024年3月現在は、SMB向けVertical SaaSとして成長してきたhacomonoをエンタープライズレベルのお客様の運用基準に引き上げるためにはどうすればよいかというテーマに取り組みはじめました。


運用保守はボクサーのパンチに例えるとジャブです。

ストレートやアッパーのような派手さはありませんが、ジャブを制したものが世界を制すというように、高レベルなOperational Excelenceが適切にコスト上昇を抑えることによって利益を最大化しInovationを生み出す新規開発の源泉としてお金や時間、メンバーのコンディションを創出していきます!

ぜひあなたもVertical SaaS界のTOYOTAを目指しているhacomono運用保守部で一緒にOperational Excelenceを追求しませんか?

ご応募お待ちしております♪

運用保守部の関連記事 techblog.hacomono.jp note.hacomono.jp


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