Amazon RDS for MySQLのメジャーバージョンを5.7から8.0にアップグレードした

はじめに

イタンジ株式会社の李です。SREとしてイタンジプロダクトの信頼性を高めたり開発の効率を向上させるなどの活動をしています。

直近Amazon RDS for MySQLのメジャーバージョンをアップグレードする機会があったので、今回はその手順と工夫したことなどをまとめてみました。

背景

弊社のプロダクトで利用するデータベースは主にMySQL 5.7を採用していました。(Auroraを使用するかRDSを使用するかに関しては、プロダクトのユースケースに合わせて対応しています)

RDSのMySQL 5.7の標準サポートの終了が今年12月中と予定されていたため、MySQL5.7使用中のDBインスタンスはメジャーバージョンのアップグレード対応が必要になりました。5.7の次に使用できるメジャーバージョンが8.0のため、今回は5.7から8.0にアップグレードするという方針で対応を行いました。

アップグレード方法の選定

MySQLのメジャーバージョンをアップグレードする方法はいくつかあります。その方法のうち、実作業の所要時間や万が一の復旧対応など色々を考えながら選定を行いました。

1. インプレースアップグレード

既存のDBインスタンスのメジャーバージョンを直接アップグレードする方法です。

実作業としては最も簡単な方法ですが、相当なメンテナンス時間が必要になり、万が一の復旧対応が必要になったらバックアップのスナップショットから新しいインスタンスを起動しなくてはいけなくなり対応時間が長くなります。

2. スナップショットリストア

既存のDBインスタンスのスナップショットから復元したDBをアップグレードする方法です。

既存のDBインスタンスがそのまま残るため、万が一の復旧対応の時間が短くなりますが、アップグレード作業にかかる時間はインプレースアップグレードとそこまで変わりません。

3. BinLogレプリケーション

既存のDBインスタンスをBinLogレプリケーションするDBを別途用意してアップグレードする方法です。

事前にレプリカDBのメジャーバージョンのアップグレードを実施し、アップグレード実作業の当時はレプリカDBをプライマリーに昇格してDB接続の向き先を切り替えるだけやれば良いので、アップグレード作業にかかる時間が短くなります。既存のDBインスタンスがそのまま残るため、万が一の復旧作業も早めに対応できます。

4. Blue/Greenデプロイ

3番の方法をAWS RDSの機能として実現したものです。

Blue/Greenデプロイを作成すると、ステージング環境が用意され本番環境のDBインスタンスと同期を行います。メジャーバージョンのアップグレードやアプリケーションの動作確認などをステージング環境で行い、実作業ではステージングと本番の切り替えを行うことでアップグレード作業ができます。

今回の対応では、3番の「BinLogレプリケーション」方法でアップグレードを実施しました。

弊社ではTerraformというツールを使用してAWSリソースをコード管理していますが、現時点でTerraformによるBlue/Greenデプロイの操作はその有効化と本番・ステージングの切り替えしかできないため、メジャーバージョンのアップグレードをコミット履歴として残すためは3番の方法が適切かと判断しました。

バージョンアップの事前準備

DBのメジャーバージョンが変わるわけなので、その影響はDBを使う側にも受けるはずです。そのため、アップグレード対象となるDBインスタンスを使用しているプロダクトの開発チームには、ローカル環境と検証環境でDBのバージョンを8.0にした時にアプリケーションの動きに致命的な影響はないか、万が一何かあったら8.0でもアプリケーションの動きに支障がないように整備をお願いしました。

その他、DBのバージョンアップの対応が更にスムーズにできるようにSREとして取り組みした内容は以下となります。

1. アプリケーションのDB参照はCNAMEレコードを使用する

アプリケーションのDB接続情報の設定でDBインスタンスの生のエンドポイントをそのまま入れたケースがたまたま発見されましたが、この場合はエンドポイントの変更が発生するとアプリケーションのソースコードを修正して再度デプロイしなくてはいけないため、その分実作業にかかる時間が長くなります。

DBインスタンスのエンドポイントをマッピングしたCNAMEレコードを作成しこれをアプリケーションから参照することで、エンドポイントの変更が起きてもアプリケーションを再度デプロイしないでCNAMEレコードの向き先を切り替えるだけでアプリケーションのDB参照を簡単に変更できます。

ただし、アプリケーションのサーバでCNAMEレコードを名前解決した結果をキャッシュにしている場合は、CNAMEレコードの向き先を変更したところで元のエンドポイントを引き続き参照しようとしていてコネクションエラーが発生する可能性があります。その場合は、アプリケーションサーバを再起動することでDBコネクションを再度貼ることができます。

2. レプリカDBの用意

本番環境のDBインスタンスをBinLogレプリケーションするインスタンスを事前に用意します。このインスタンスでメジャーバージョンアップをあらかじめ実行しておきます。久しぶりのDBメンテナンスだったので、今回の対応ではメジャーバージョンのアップグレードだけでなく、サブネットグループの変更やインスタンス設定の変更など中々対応できなかった技術的な負債の解消も行いました。

3. アップグレードチェッカーの実行

MySQL Shellユーティリティーを使用することで、MySQLメジャーバージョンのアップグレードの準備ができているかを事前にチェックすることができます。今回のケースでは、ROW_FORMATがレガシーだったり不正なDATA型のデータが入っているなどの異常が検出されたため、対象DBインスタンスのオーナーであるプロダクト開発チームに共有して異常を解決していただきました。

アップグレードの実作業

メンテナンス当時で行った実作業の手順です。

1. DB書き込み作業の停止

アプリケーションサーバとバッチ処理を停止するなどの対応で書き込みが全く発生しないようにします。この際に、DBインスタンスのメトリクスとMySQLのプロセスリストをチェックすることでDB書き込みが発生していないことをチェックしましょう。

  • プライマリーインスタンスのDatabaseConnections ⇒ DBコネクション数。レプリカDBがレプリケーションのためコネクションを使用しているので、それ以外のコネクションがないことを確認
  • レプリカインスタンスのReplicaLag ⇒ レプリケーション遅延。このメトリクスが0になったらプライマリーとレプリカが同期していると言える。

2. レプリカDBの昇格

レプリカDBのBinLogレプリケーションを切り離してプライマリーに昇格します。作業中の体感でいうと大まか10分ぐらいかかりました。

3. CNAMEの向き先を新しいDBインスタンスのエンドポイントに変更する

CNAMEレコードの向き先をMySQL5.7のものからMySQL8.0のものに切り替えします。長くても2分で終わります。 踏み台サーバなどでVPC内部に接続してdigコマンドを使用することで、向き先の変更が終わったかを確認することができます。

4. DB書き込み作業の再開

1番の作業で停止させたアプリケーションとバッチ処理を再開します。動作確認を行なって動きに異常がないことが確認できたら、これでDBアップグレード作業は完了です。

終わりに

今回はMySQLのメジャーバージョンのアップグレードについてまとめてみました。

DBのメジャーバージョンのアップグレードを実施すると決めた最初は、アプリケーションのインフラの最もコアなところを触るわけなのでうまくいけるか多少恐れていましたが、気を引き締めて事前に関連のナレッジをしっかりためて検証を繰り返すことで、実作業では大した問題なくスムーズにいけたかと思います。

参考の記事