📚

Game8.jpのデータベースをMySQL 5.7から8.0へ無停止アップグレードしました🎉

2023/12/25に公開

はじめに

MySQL8.0と互換性のあるAmazon Aurora MySQL 3は、2021年11月にリリースされ早2年が経過しました。
弊社では可能な限りマネージドに乗っかる方針でインフラを運用しており、新しいバージョンは便利な機能が発表されても利用できない傾向にあることもあり、これまで見送ってきました。

Game8.jpでは、データベースサービスとしてAWSのAurora(MySQL)を利用しており、上記方針によりAurora MySQL 2を利用してきましたが、

  • 標準サポート終了が来年10月に迫っている
  • 分析に必要な機能やパフォーマンス面で8.0が必要
  • MySQL8.0が主流になっており、5.7を使い続けることよりも懸念材料が少ない
    という判断をしまして、本日🎄クリスマス🎄の夜にアップグレードしました🎅🎉

これまでのGame8.jpのデータベース変遷としては、
オンプレ?(入社前) → RDS(MySQL5.6) → Aurora(MySQL5.6) → Aurora(MySQL5.7) → Aurora(MySQL8.0)
となっており、私が入社後は全てサービス無停止でアップグレードをしてきております!

本記事では、簡単ではありますが、手法やポイントなどをお伝えしていきます。

Auroraの移行手順について

AWSのマネージド手順はどうか

Aurora2から3への移行手順として、おそらく一番簡単なのがインプレースアップグレードの実行です。
この手順を実行すると安全・簡単にアップグレード出来ますが、どうしてもダウンタイムが発生してしまうため利用場面は限られてしまいます。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Updates.MajorVersionUpgrade.html#AuroraMySQL.Upgrading.Procedure

これを解決できるのがAmazon RDS ブルー/グリーンデプロイです!
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/blue-green-deployments-overview.html

Game8.jpに適用できるのか

…と言いたいところですが、、、Game8.jpではバックグラウンド処理に掛かる負荷を分散させたく、クラスター間のレプリケーションを設定しているため、全ての系統について同期を掛ける必要があります。

それに加えて、テキストエンコーディングや照合順序についても、5.7系とは別に8.0系用のパラメータを用意する必要があり、従来の手順どおり自前で実行すべきと判断しました。

具体的な移行手順(準備編)

基本的には、クラスター間のレプリケーションと同様の考え方となります。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.MySQL.html

  1. ライターインスタンスのbinlogを有効にする。
    • binlogを有効にするためにはパラメータグループを設定する必要があります。
    • パラメータグループを有効にするためにはインスタンスの再起動が必要となりますが、クラスターに対して設定後、リーダーを追加すると設定したパラメータが有効になるので、このインスタンスを昇格させます
  2. binlogが有効になったライターインスタンスでスナップショットを作成する。(手順ミスかもしれませんがリーダーインスタンスで実行するとレプリケーションに必要な情報が取れませんでした)
  3. スナップショットから復元する
    • 復元の際は、現状と全く同様の設定にすることを推奨します
    • (アップグレードはまだです)
  4. レプリケーションの事前準備を行う
    • 復元が完了するとイベントにbinlogのfilenameとpositionが取れるのでメモ
    • セキュリティグループでマスターのDBに接続出来るようにしておく
  5. レプリケーションの設定
    # マスターに接続
    CALL mysql.rds_set_external_master ('%{DATABASE_HOST}', 3306, '%{DATABASE_USER_NAME}', '%{DATABASE_PASSWORD}', '%{4で拾ってきたfilename}', %{4で拾ってきたposition}, 0);
    
    # レプリケーションを開始
    CALL mysql.rds_start_replication;
    
    # show slave status;
    # いろいろ出てくる
    
    # 止めたいときはこれ
    CALL mysql.rds_stop_replication;
    
    # レプリケーションが必要なくなったらこれ
    CALL mysql.rds_reset_external_master;
    
  6. スレーブ側( show slave status )で、 Slave_IO_RunningとSlave_SQL_Runningが共にyesになることを見守る(その後もずっとyesであること)
  7. マスター側( show master status )とスレーブ側( show slave status )で同期状態をチェックし追いついたら同期完了

  8. レプリケーション先のAuroraに対してインプレースアップグレードを実行する
    • この際、パラメータグループはAurora 3用のものを事前に用意しておき設定する
  9. アップグレードが完了したらしばらく流しておきレプリケーションが止まらないことを確認する
  10. 大丈夫そうであれば、Game8.jpの場合はクラスター間のレプリケーションが必要なため、同様の手順で、レプリケーション先→レプリケーション先の先へとレプリケーションを設定する
    • レプリケーション元ではなくレプリケーション先のクラスターからスナップショットを取得する
    • レプリケーション先は既にAurora3なので、立ち上げるクラスターも最初からAurora3
  11. レプリケーションが設定されたら見守る

ここまで来るとこうなります

具体的な移行手順(いざ移行)

この状況では、システムとしては次のような状態になっています。

  • レプリケーション元はAurora2だが、レプリケーション先はAurora3である
  • レプリケーション先の先まで最新データが維持されており、かつ動作にも問題がない
  • レプリケーション先でINSERTを発生させようものならその時点でレプリケーションが止まる

3つ目で急に物騒な話になってまいりました。
そうなのです、レプリケーションを設定しているときに一番ケアすべきこと=衝突を回避して、ことを成し遂げなければいけません。

幸い、Game8.jpではINSERTが発生する場面が”ほぼ”限られます。

  1. (ユーザー利用)掲示板への書き込み
  2. (ユーザー利用)ユーザー登録
  3. (ユーザー利用)ツール系の記録
  4. (社内利用)記事の作成

お察しの通り、1と4は激しく、特に4に対して抗う術は有りません。通常業務時間中に入れ替えるなんてことは実現性が皆無です。もちろん掲示板への書き込みも毎秒単位で発生するので難しいのですが…深夜対応ですね、やはり。
🎄クリスマス🎄には🎅が深夜対応する、この記事ではこれだけ覚えて帰って構いません。

話の流れがややこしくなりましたが、何も人がいない時間帯を狙って「エイヤ」でやろうという話では有りません。

  • INSERTが発生する場面が限られ、
  • かつそれがサービスとしてのメイン機能でないのであれば、

一時的にその機能を止めることで無停止アップグレードが出来る、ということです。

今回はその詳細については割愛しますが、そのような手順を経て、5分程で新しいクラスターへの移行が完了しました。
完了後は、 CALL mysql.rds_stop_replication; CALL mysql.rds_reset_external_master; でレプリケーションを止めることを忘れないようにしましょう。

最後に

駆け足で来てしまいましたが、なんとなく伝わりましたでしょうか。
この記事だけ見ると突貫工事のように見えるかもしれませんが、実際はそんなことはなく、

  • MySQL5.7と8.0の特性について理解し適用に問題がないことを事前に確認済みで
  • 他のサービスで運用経験も積み
  • 確立した手順で新規サービスにおいて練習を積み
  • 満を持して臨んでいる

ということは最後にお伝えしておきたいと思います。

個人的に今回のアップグレードでCTEやウィンドウ関数が使えるようになりすごくハッピーです!

🎅

それでは良いクリスマスを送るのじゃ🎄
ホッホッホ

ゲームエイトテックブログ

Discussion