Chapter 07

修正アプリケーションリリース・移行実施のフェーズ

hmatsu47
hmatsu47
2023.01.15に更新

この章について

性能試験、修正完了したアプリケーションのリリース、そして移行実施日の前後を振り返ります。

性能試験・負荷試験(2022/9)

本番相当のデータ・負荷をベースに、その時点の最新版のアプリケーションで性能試験(負荷試験)を実施しました。

オプティマイザヒントを使って SQL 文の実行計画を調整

Performance Insights を確認し、明らかに負荷が上がりレスポンスタイムが長くなった SQL 文が 2 つ見つかりました。

それらと同様の問題が生じそうなものを含め、数個の SQL 文をオプティマイザヒントを使って調整しました。

https://qiita.com/hmatsu47/items/9b1090111f2683d386bc

Reader インスタンスを活用

2 つあるうちの小さいほうのクラスタでは Reader インスタンスを使用していなかったので、Performance Insights を見て上位にあたる SQL 文の中からSELECT文だけ抜き出し、関連するものを含めて Reader インスタンスにアクセスするようアプリケーションを修正しました。

メインのクラスタのスケールアップを検討

もう一方のメインのクラスタでは、Writer インスタンスの CPU 使用率が 100% に到達しました。

実際にはレスポンスが多少遅くなる程度でエラーは発生しなかったのですが、以前からバッファプール不足が原因でアプリケーションの一部に遅い機能が存在し問題になっていたので、移行のタイミングでスケールアップする検討を進めました。

修正完了したアプリケーションをリリース(2022/10)

DB を移行する前に、v1 の DB の環境で、修正したアプリケーションをリリースしました。

この前後に、以下の 2 点の問題が発覚しました。

MySQL Connector/J を使ってFLOAT(M,D)DOUBLE(M,D)型の列をjava.math.BigDecimal値として取り込む際の挙動変化

MySQL Connector/J 5.1 時代はDの値が自動的にBigDecimal値のスケール(小数点以下の桁数)に指定されましたが、これらの桁数指定が非推奨に変わった影響か、MySQL Connector/J 8.0 ではスケールの自動設定が削除され、明示的にsetScale(D)する必要がありました。

DATE型の値と文字列を比較する際の挙動変化

こちらで触れられている問題です。

https://rabbitfoot141.hatenablog.com/entry/2020/07/01/215728

文字列(空文字列を含む)を日付と比較している箇所で、以前はエラーにならずに単なる文字列比較として処理されていたものがエラーに変わりました。

移行先 DB およびレプリケーション設定(2022/10)

移行作業直前に 本番 v1 DB のスナップショットから v2 の 中継用 DB、さらに v3 の新本番用 DB を作成しました。

そして、それらの間で binlog レプリケーションを設定しました。

メインのクラスタをスケールアップ

メインのクラスタは結局スケールアップすることになりました。

それに伴い、小さいほうのクラスタも db.r5.xlarge から db.r6g.xlarge に変更することになりました(リザーブドインスタンス追加購入の関係で、変更が可能に)。

当日移行作業(2022/10)

あれだけ念を入れて事前確認したデータ整合確認で、まさかの不整合が発覚。

原因は 2 つありました。

メンテナンスに入る前のバッチ処理の処理時間が延びていて、データ整合確認のタイミングに実行されていた

止めても問題のないバッチ処理だったので中断し、データもサービス提供に支障のないものだったので差異を無視しました。

主キーのないテーブルが紛れ込んでいた

内規で作成不可にしていた主キーのないテーブルが見つかり、そのデータのダンプファイル内での出力順が入れ替わっていただけでした。

アプリケーションの動作に直接関係するテーブルではなく、特に問題がなかったのでそのまま進めました。

また、これらのデータ不整合の原因調査で 40 分ほど作業時間が延びてしまったことで、別の問題が発生しました。

サービス再開前に(バッチ処理とは別の)定時実行処理が実行された

Web サーバの起動処理だったので、サービス再開を準備している最中に意図せずサービスが再開される事態に。

大きな問題には繋がりませんでしたが、影響を確認するためにサービス再開後に調査が必要になり、予定していた作業時間を 3 時間以上オーバーしてしまいました(さっさと帰って寝るはずだったのが、昼近くに帰ることに。太陽が眩しかったです)。


2023/1/15 追記:

サービス再開後、binlog レプリケーションを逆方向に切り替えるときにレプリケーションエラーが発生

一つ書き忘れていたので追記します。

この移行作業では、遠隔バックアップ用の DB について、

  • v3 移行前は v1 の本番 DB から v2 の中継用 DB および v3 の遠隔バックアップ用 DB を経て v3 の新本番 DB に binlog レプリケーション
  • v3 移行後はこれらの binlog レプリケーションをリセットして、v3 の新本番 DB から v3 の遠隔バックアップ用 DB に binlog レプリケーション

という流れで、v3 の DB と遠隔バックアップ用 DB(v3)の binlog レプリケーションの方向を逆転させました。

このとき、

  • 全てのレプリカ(スレーブ)DB でCALL mysql.rds_stop_replication;
  • (サービス停止状態でデータ整合確認などの各種作業を実施)
  • v3 の新本番 DB でCALL mysql.rds_reset_external_source;
  • v3 の遠隔バックアップ用 DB でCALL mysql.rds_set_external_source(【Source 接続用の設定値】);
  • v3 の遠隔バックアップ用 DB でCALL mysql.rds_start_replication;

という流れで進めようとしたところ、ソース DB の切り替え(最後から 2 つ目)で

ERROR 1371 (HY000): Failed purging old relay logs: Failed during log reset

が発生しました。

v3 の遠隔バックアップ用 DB でSHOW REPLICA STATUS\Gしたところ、

  • ソース DB の設定は新しいものが入っている
  • 以前の relaylog が残ってしまっている

ことが分かり、

http://blog.livedoor.jp/harukisan7/archives/32943403.html

を参考にして、v3 の遠隔バックアップ用 DB で

  • 一旦CALL mysql.rds_start_replication;でレプリケーションを開始
  • SHOW REPLICA STATUS\Gでレプリケーションが進んでいないことを確認
    • Replica_SQL_Running:No
  • この状態でCALL mysql.rds_reset_external_source;
  • あらためてCALL mysql.rds_set_external_source(【Source 接続用の設定値】);
  • もう一度CALL mysql.rds_start_replication;

を実行したところ、正しくレプリケーションできる状態になりました。


切り替え後の作業(2022/10)

旧 DB の停止とスナップショット化、監視対象の切り替え、スケールアップに伴うリザーブドインスタンスの追加購入を行いました。

一部、監視項目の変化(バージョン間差異)が発生しましたが、概ね順調に進みました。

ただし、このタイミングで MySQL Router を使っている特殊なバッチ処理の実行トラブルが発覚しました(移行当日の確認では問題なかったのになぜかその後失敗し続けていた)。

MySQL Router もマイナーバージョン間で設定や挙動に差異があるので、注意が必要です。