Yappli Tech Blog

株式会社ヤプリの開発メンバーによるブログです。最新の技術情報からチーム・働き方に関するテーマまで、日々の熱い想いを持って発信していきます。

MySQLバージョンアップ(5→8系)を行った時の手順について紹介

概要

こんにちは、サーバーサイドエンジニアの佐野きよです。

この記事では、弊社が実施したAurora MySQLのバージョンアップ(5系から8系へ)について、その手順や注意点を共有します。 システムの安定稼働を維持しつつ、いかにして安全にアップグレードしたか、その過程で得られた知見が、同様の課題に直面している開発者の皆様の参考になれば幸いです。

前提

今回のバージョンアッププロジェクトにおけるシステムの技術スタックは以下の通りです。

  • クラウド: AWS
  • フレームワーク: Laravel
  • インフラ: Amazon ECS (Fargate)
  • データベース: Amazon Aurora (MySQL互換)

影響範囲調査

バージョンアップにあたり、まず最初に行ったのが影響範囲の調査です。MySQL 5.7から8.0へのアップグレードは、多くの変更点が含まれるため、公式ドキュメントを参考に慎重な洗い出しが必要でした。

dev.mysql.com

特に、注意が必要だと判断した点は以下の通りです。

予約語の追加

MySQL 8.0では新しい予約語が追加されています。これにより、既存のテーブルやカラム名が予約語と衝突するとエラーとなります。 例えば、RANK, DENSE_RANK, ROW_NUMBER などのウィンドウ関数に関連するキーワードが予約語になりました。

-- MySQL 8.0ではエラーになる可能性があるクエリの例
SELECT id, `rank` FROM users;

上記のようなクエリは、バッククォートで囲みエスケープすることで回避できるので大きな問題にはならないですが、影響範囲は広いので注意が必要です。
特にRedashやTroccoなど、アプリケーション以外の場所からDBが参照されている箇所は考慮が漏れ易いので注意しましょう。

GROUP BY句の ASC/DESC 修飾子の削除

8.0ではこの構文がサポートされなくなりました。並び順を制御したい場合は、ORDER BY 句を明示的に使用する必要があります。

-- MySQL 5.7 (動作する)
SELECT age, COUNT(*) FROM users GROUP BY age DESC;

-- MySQL 8.0 (エラーになる)
SELECT age, COUNT(*) FROM users GROUP BY age DESC;

-- MySQL 8.0 (修正後)
SELECT age, COUNT(*) FROM users GROUP BY age ORDER BY age DESC;

デフォルト文字セットの変更

デフォルトの文字セットが latin1 から utf8mb4 に変更されました。 弊社のシステムではもともとLaravelのdatabase.phputf8mb4 を使用していたため直接的な影響は少なかったですが、新規でテーブルを作成する際や、文字セットを明示的に指定していない箇所で意図しない挙動が起きないかを確認しました。

移行期間中、5系と8系のCIを並行して動かすように

バージョンアッププロジェクトが進行中であっても、アプリケーションの新規機能開発を止めることはできません。そのため、開発中の新しいコードがMySQL 8.0でも正しく動作するかを常に確認できるようにするため、既存のCI(継続的インテグレーション)環境を拡張し、従来のMySQL 5系に加えてMySQL 8系でのテストも並行して実行するようにしました。これにより、すべてのプルリクエストで新旧両方のバージョンでの動作が自動的にテストされ、開発者は自身の変更が与える影響を早期に把握できるようになりました。

バージョンアップ戦略の検討

ダウンタイムを最小限に抑えるため、Auroraの Blue/Greenデプロイ を採用することにしました。

Blue/Greenデプロイは、現在の本番環境(Blue環境)とは別に、新しいバージョンのDBクラスター(Green環境)を構築し、両者をレプリケーションさせます。準備が整ったら、スイッチオーバー機能を使ってトラフィックをGreen環境に切り替えます。

この方法の最大のメリットは、ダウンタイムが非常に短いことです。(弊社の場合、切り替えにかかる時間はおおよそ1分程度でした。)

docs.aws.amazon.com

注意点: Blue/Greenデプロイを利用するには、対象のAurora DBクラスターで binlogが有効になっている必要があります。binlogを有効化するにはDBクラスターの再起動が必要になるため、あらかじめ計画的に有効化しておくことをお勧めします。

動作検証

影響範囲調査で洗い出した項目以外にも、予期せぬ非互換性が存在する可能性があります。そこで、本番環境で実際に実行されているクエリを用いて、より網羅的な動作検証を行いました。

具体的には、ステージング環境のDBのクエリログ(general_log)を一定期間取得し、そのログに含まれるSQLを、用意した5系と8系の両方のテスト用DBクラスタに流し込みます。そして、それぞれのレスポンスを比較し、差分がないかを確認しました。(本番DBで実施しなかったのは、general_logをオンにすることでパフォーマンスに影響が出る懸念があったため)

この手法により、アプリケーションコードからは見えにくい、フレームワークやライブラリが自動生成するクエリの問題も検出することができました。

動作検証の具体的な手法については、弊社の以下の記事で詳しく解説しています。

tech.yappli.io

スロークエリを利用したパフォーマンス検証

機能的な問題だけでなく、パフォーマンスの劣化も防ぐ必要があります。実際、動作的なところは概ねフレームワークが吸収してくれるので、パフォーマンスの劣化が一番の懸念点かと思います。MySQL 8.0ではオプティマイザが改善されており、多くのクエリは高速化が期待できますが、逆に性能が劣化するケースもゼロではありません。

すべてのクエリのパフォーマンスを比較するのは現実的ではないため、スロークエリ(実行に1秒以上かかっているもの)に絞って調査を行いました。

動作検証と同様に、5系と8系のクラスターを用意し、スロークエリログに出力されたクエリを両方で実行。実行時間に著しい差が見られたものをリストアップし、インデックスの追加やSQLの修正といったチューニングを行いました。

パフォーマンス検証の具体的な手法については、弊社の以下の記事で詳しく解説しています。

tech.yappli.io

社内調整

技術的な課題の解決と比較して、もうひとつ重要なのが社内調整です。正直なところ、ここが一番大変な作業でした。弊社の場合、以下のようなことを実施しました。

  • 利用者への事前告知: メンテナンスの実施について、サービスの利用者への事前告知を行いました。
  • 実施日時の確定: ダウンタイムを伴う作業時間を確定させるため、判断材料を揃える必要がありました。特に、弊社のシステムは多くのバッチ処理が夜間から早朝にかけて実行されていたため、それらの影響を最小限に抑える時間帯を見つける必要がありました。
    • すべてのバッチの実行時間とビジネス上の用途をリストアップし、影響が少ない時間帯を探しました。
    • 社外のシステムと連携しているバッチも多く、それらの関係者との調整には特に骨が折れました。バッチの実行時間を一時的に変更してもらったり、場合によってはメンテナンス時間中はスキップさせるといった交渉も必要でした。

まとめ

MySQLのバージョンアップは、単なる技術的な作業ではなく、計画、検証、そして多くの関係者とのコミュニケーションが求められる一大プロジェクトです。この記事が、皆様のバージョンアップ計画の一助となれば幸いです!

さいごに

ヤプリではサーバーサイドエンジニアを随時募集しています! 興味を持った方、是非一度カジュアル面談を受けてみませんか…??

open.talentio.com

最後まで読んでいただきありがとうございました!