AWS RDS Aurora MySQL v1(5.6互換)→v2(5.7互換) へのインプレースアップグレードに向けての注意とアドバイス

本記事は [Craft Egg Advent Calendar 2022](https://qiita.com/advent-calendar/2022/craftegg)の8日目の記事です。

## はじめに
株式会社Craft Eggでバックエンドエンジニアをしております高川です！

今年は何を書こうかなとずっと考えていたのですが、直近の業務で大変だったAurora MySQLのインプレースアップグレードについて書きます。Aurora MySQL v1 (5.6互換)は2023年2月末にEOLを迎えるため、今が旬(ちょっと遅い?)かなと思っています。

記事執筆時には、まだサービスの本番環境でアップグレードは実施してないのですが、開発環境やステージング環境でアップグレードして得た知見とこうしたらやりやすいかもというアドバイス(主観)をお伝えしますので、アップグレードに悩み苦しんでいる同志たちの助力になれば良いなと思います！

これだけは先に伝えたいのですが、<font color="red">**Terraformでアップグレードするのはやめた方がいいかもしれません。**</font>

私も最初はTerraformで実行していたのですが、一度クラスタを削除してから再度作るという挙動をするみたいで、何度もデータが消えました。削除しない方法があるのかもしれませんが、管理コンソールから実行するのが一番安心です。

## アップグレードに向けて何をしないといけないのか
アップグレードするために、ざっとやることを書いてみます。

1. アップグレードによる影響内容調査
2. パラメーターグループの調整
3. アップグレード前にスナップショットを作成
4. アップグレードしてみる

#### 1. アップグレードによる影響内容調査
一般的に、アップグレードすれば性能が良くなることは多いですが、最適化の中身が変わっており、現状のままだと逆に性能が悪くなるといったことも珍しくありません。

当然、アップグレード先のMySQL 5.7で何が変わったのかを把握する必要がありますが、MySQL 5.6のマイナーバージョンのアップグレードでもたまに影響のある変更があったりもするので注意したいです。[公式ドキュメント](https://dev.mysql.com/doc/refman/5.7/en/mysql-nutshell.html
)に全て書かれていますが、世の中には同じような辛い思いをしてる人がたくさんいて解説もしている記事も多いので、そちらを参考にするのが良いです。

私が調査した際には以下の観点でみてました。
- **パフォーマンス低下に繋がる内容がないか**
    - 最適化の挙動が変化してないか
        - 例：システム変数の設定やwhere句の条件によってはインデックスを使わずフルスキャンになってしまうこともある（参考：[MySQLでIN句の中に大量の値の入ったクエリがフルスキャンを起こす話](https://developers.freee.co.jp/entry/large-in-clouse-length-cause-full-scan)）
    - システム変数の名称が変化していて設定が漏れる
        - 例えば、パラレルクエリを有効にする変数は`aurora_pq`から`aurora_parallel_query`に変わっており、`aurora_parallel_query`のデフォルト値は無効になっています
- **現状のまま運用できるか**
    - クエリの書き方が変わらないか
    - 予約語が増えてないか
    - ORマッパーは対応してるのか

#### 2. パラメーターグループの調整
Auroraではシステム変数をパラメーターグループで設定します。デフォルトのパラメーターグループではなく、カスタマイズされたパラメーターグループを使用している場合は、v2用の設定をDBクラスターとDBインスタンスに対して別々で作成する必要があります。

**どんなパラメーターが追加されたか変更されたかを書いた方が有意義そうなので、記事の後ろの方で記述します。**

今回のようなv1からv2へのアップグレードでは、v1で設定していた値をv2でも設定する必要があります。名称が変わっていることも普通にありますので、設定されているパラメーターを比較して把握していくのが楽だと思います。

私の場合は、下記のコマンドを使い、得られたcsvをスプレッドシートに貼り付けて、VLOOKUPなどの関数で整形したりしました。

```インスタンス用のパラメーターグループ設定をcsvで取得.
aws rds describe-db-parameters \
--region ap-northeast-1 \
--db-parameter-group-name "インスタンス用のパラメーターグループ名" \
| jq -r '["名前","値","許可された値","変更可能","送信元","適用タイプ","データ型","説明","ApplyMethod","MinimumEngineVersion"], (.Parameters[] | [.ParameterName,.ParameterValue,.AllowedValues,.IsModifiable,.Source,.ApplyType,.DataType,.Description,.ApplyMethod,.MinimumEngineVersion]) | @csv' \
| iconv -t sjis \
> parameters-instance.csv
```

```クラスタ用のパラメーターグループ設定をcsvで取得.
aws rds describe-db-cluster-parameters \
--region ap-northeast-1 \
--db-cluster-parameter-group-name "クラスタ用のパラメーターグループ名" \
| jq -r '["名前","値","許可された値","変更可能","送信元","適用タイプ","データ型","説明","ApplyMethod","MinimumEngineVersion"], (.Parameters[] | [.ParameterName,.ParameterValue,.AllowedValues,.IsModifiable,.Source,.ApplyType,.DataType,.Description,.ApplyMethod,.MinimumEngineVersion]) | @csv' \
| iconv -t sjis \
> parameters-cluster.csv
```
整形した結果、以下の画像のような形になりました。値が一致してない箇所に色をつける条件付き書式を設定するとわかりやすかったりします。
![スクリーンショット 2022-11-30 21.06.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308624/246e9e24-cb22-afb5-39fe-db715b54718f.png)

#### 3.アップグレード前にスナップショット
ここまで来たらアップグレードするだけですが、一旦落ち着いてスナップショットを作成しましょう。何か起きたら消えるということを念頭に置いて対応しましょう。

#### 4.アップグレードしてみる
冒頭でも記述した通り、Terraformを用いたアップグレードは削除した後に作成するという挙動をするため、管理コンソールから実施するのをお勧めします。

※いきなり本番環境に反映する人はいないと思いますが、まずは開発環境で試してみて、パフォーマンスの低下がないか、その他運用に影響がないかを確認するための期間をとって、問題がないことを確認したら、ステージング、本番に反映するという流れでアップグレードしていきましょう

- アップグレード時の注意点
    - アップグレード時の管理コンソール画面で**カスタムパラメーターグループを設定してアップグレードすることができますが、再起動しないと反映されません。**
    - **インスタンスのマイナーバージョン自動更新の設定がなぜか有効になる可能性があるので、自動更新したくない場合はOFFにしましょう。**


## v1とv2のパラメーターグループの内容差分
所属PJTで対応しなければいけなかったものだけ記述するので、全てを網羅してるわけではないことをご了承ください。
- aurora_pq, aurora_pq_supported
    - 5.7では削除され、aurora_parallel_queryに統合
- internal_tmp_disk_storage_engine
    - ５.7で追加
    - 結合などで使われる内部一時テーブル(ディスク)で使うエンジンの選択
    - 元々5.6ではMyISAMだけだったのが、5.7ではInnoDBも選択可能になった
- performance_schema_〇〇
    - ５.7で追加
    - 統計情報を管理するテーブルの設定です
    - AWS RDSのPerformance Insightsを有効すると勝手に値が入ってきます
- range_optimizer_max_mem_size
    - ５.7で追加
    - in句などの範囲検索で使えるメモリサイズ
    - 上の方で紹介したパフォーマンス影響のある例の要因の一つです
    - 候補となるインデックスで使用するメモリサイズは変わります
- show_compatibiility_56
    - ５.7で追加
    - performance_schemaでもinformation_schemaと同じような情報が観れるので、`SHOW VARIABLES`や`SHOW_STATUS`がどちらを見るかを設定します
    - 有効ならinformation_schemaを見て、無効ならperformance_schemaを見るようになります


## まとめ
色々書きましたが、様々な記事の書いてある通りにやっても公式ドキュメント通りにやっても、結構つまずきポイントがあります。一件一件調べながら対応するしかなく、本当に大変だと思いますが、着実に自分自身のスキルアップに繋がっているはずなので、前向きに計画的に取り組んでいきましょう！

v2は2024/2/29あたりにEoLなので、次はv3(MySQL 8.0)へのアップグレードですね…共にがんばりましょう