コネヒト開発者ブログ

コネヒト開発者ブログ

RDS for MySQLからAuroraへの移行 〜Auroraリードレプリカを利用した低コスト移行方式〜

こんにちは。インフラエンジニアの永井(shnagai)です。

今回は、メインサービスで使っているDBを、RDS for MySQLからAmazon Auroraへ移行した話について書こうと思います。

Auroraの良さについては、一つ前のブログにまとめているので気になる方はこちらをご覧ください。

tech.connehito.com

なぜAurora移行を行ったのか

可用性を担保しながら、コストメリットが享受できる

RDS for MySQL時代は可用性を確保する為に、マスター、レプリカ全て MultiAZ構成で組んでいました。しかし、MultiAZだとアクティブ-スタンバイ構成なので、スタンバイ機はトラフィックを捌かず寝ている状態になります。

Auroraにすることで、マスター - レプリカ間のフェイルオーバーが可能になり、全てのRDSインスタンスをアクティブに運用することで、同じマスタとレプリカの台数で運用した場合に、コスト削減が図れます。

運用面のメリットを享受したかった

下記にあるような、Auroraが提供している機能を使うことでDBA的な仕事を出来るだけ減らし運用負荷なくサービス運用が可能になります。

  • リーダエンドポイントでの、リードレプリカへのヘルスチェック付きLB機能
  • アプリケーションからのセッション切断なく行われる、ゼロダウンタイムパッチ
  • パフォーマンス劣化の少ない AuditLogでの監査(MySQLだとパフォーマンス 1/3程になるという話で使いづらかった)
  • 最近GAされたパフォーマンスインサイトやCloudWatchでDBエンジン関連のものが見れることで、何もしなくても詳細なモニタリングが可能になる

Aurora移行後のアーキテクチャ f:id:nagais:20180828130021j:plain

Aurora移行でのメイン検証

メインデータベースの移行だったので、慎重な検証を重ねた末に移行を行いました。 時系列での、移行プロセスは後述するので、ここでは検証時に特に注力した2点について書こうと思います。

①DBエンジンがMySQL5.6からAuroraに変わることで、アプリケーション側で予期せぬエラーや性能劣化が発生しないか

AuroraはMySQL5.6互換で、移行前はコネヒトでもMySQL5.6を使っていました。 AWS SAに聞いたり公式ドキュメントを見ながら、ある程度Aurora自体枯れてきていて、他社での移行実績もあるので、Aurora移行対策でのアプリケーション修正は不要だろうと踏んでいました。

しかし、やはり不安はあったので、事前検証として、ステージング環境のAurora化・本番環境での読み取りトラフィックへのAuroraのカナリアリリースを通して、実際のトラフィックを裁く中で、もしエラーを検知した場合は、アプリケーションを修正するというスタンスを取りました。

結果として、Aurora導入にあたりアプリケーション側の改修は0でした。アプリケーション起点で工数をかけて調査するのではなく、カナリアリリースで本番トラフィックを受けるこの方法は、クラウドネイティブな考えに通ずるところがあり個人的には気に入っています。もちろんユーザに迷惑をかけないために、ステージングである程度試験してからカナリアリリースは行っていますが。

②MySQLからAuroraへのマスター(書込トラフィック)切替時のオペレーション

今回の、Aurora移行は、オンライン中に行いました。(ユーザへのメンテナンス周知等はもちろん行ってます) メインDBの切替ですので、書込トラフィックをいかに短時間でRDS for MySQLからAuroraに切替られるのかが移行の肝でした。当日作業でのダウンタイムを小さくすることを重要視しプランを練り、ステージング環境の切替時に実際のオペレーションを行いつつ、時間計測も行いました。

一番迷ったのは、切替時の書込データロストを防ぐ為の書込トラフィック遮断の方法です。ダウンタイムを小さくする事を最優先したので、RDSマスタをリードオンリーモードにするのが正攻法なところですが、SecurityGroupを使い、L4レイヤでMySQLへの通信を遮断する方法を選択しました。

以下が、検証の結果書込トラフィック移行の最終的な流れです。やること自体はとてもシンプルな内容になりました。

MySQLへの書込トラフィックを遮断(Route53の切替)
 - Route53の書込用DBレコードを、Auroraのリーダエンドポイントに切替(アプリケーションは書込トラフィックのみエラー検知)
 - アプリケーション側でセッションを使い回す可能性があるので、セキュリティグループにてMySQLマスターへのMySQL通信遮断
↓
最終書込のAuroraへのレプリケーション確認
↓
Auroraマスター昇格
↓
書込トラフィックをAuroraへ切替(Route53)

時系列で見たAurora移行の流れ

ここからは、実際にコネヒトで行った、RDS for MySQL5.6からAmazon Auroraへの移行について手順を、時系列で解説しようと思います。作業を出来る限り分解して、④までの作業は事前作業として、実際の深夜の切替作業は、⑤の書込トラフィックの切替のみで済むように設計しました。

【移行ステップ】

①Auroraリードレプリカを本番の読み取りトラフィックにカナリアリリース

②ステージング環境を、Aurora構成に切替

③本番の読み取りトラフィックを100%Aurora化

④サービス用途以外のレプリカDBを、Auroraをマスターとするbinlogレプリにて作成

⑤書込トラフィックのAuroraへの切替

ざっくり言うと、RDS for MySQLから作成出来るAuroraリードレプリカを使ったAurora移行形式です。RDS for MySQLからの移行だと、DMS(AWS Database Migration Service )を使うまでもなく、手軽にAurora移行が実現出来ます。

移行前の状態

まずは、Aurora移行前のアーキテクチャを簡単に紹介しておきます。

  • サービスで使っているRDS for MySQLは、可用性を確保するために全てMultiAZ構成
  • アプリケーションからのread only通信は、Route53で負荷分散(ヘルスチェックは使えないので、MultiAZ構成で可用性担保)
  • データ分析等に使うため、別サブネットにもRDSレプリカを配置し、社内から直接参照

f:id:nagais:20180828130053j:plain

以下、各ステップについて解説していきます。

①Auroraリードレプリカを本番の読み取りトラフィックにカナリアリリース

便利なことに、RDS for MySQLのレプリカとしてAuroraリードレプリカを作成することが出来ます。(異なるデータベースエンジンでデータの同期が出来るってすごい活気的だなと思います) アプリケーション側で予期せぬ挙動が発生しないかを確認するため、2週間程Auroraリードレプリカを本番の読み取りトラフィックにカナリアリリースしました。

カナリアリリースは、Route53の重み付けレシオ(Weight)を利用して行っています。 徐々に比率を上げていき、50%ずつ振り分けている時に、DBエンジンとしての性能差やホスト側の負荷状況も比較を行いました。コネヒトでは、潤沢なメモリのインスタンスを利用しているので、ほぼバッファキャッシュで返しており、Auroraによる大幅な性能向上は計測されませんでしたが、AuditLogを有効化した状態でもレイテンシ悪化しない事を確認出来ました。 このステップで、アプリケーション側で予期せぬエラー等何も問題が起きなかったのでAurora移行の実施を決定しました。

f:id:nagais:20180828130104j:plain

②ステージング環境を、Aurora構成に切替

次に、RDS for MySQLで稼働していたステージング環境を、Auroraに切替えました。 ここでの切替の目的は下記2つです。

1.カナリアリリースでは確認出来なかった、書込系処理でアプリケーション側の予期せぬエラーが出ないかのチェック

2.本番同等の手順で実施し、手順に漏れがないかのリハーサル的役割

問題なくステージング環境の移行は成功し、ここでも2週間程意図せぬ問題が出ないかウォッチを続けました。

③本番の読み取りトラフィックを100%Aurora化

Auroraに切り替えても、アプリケーション的に問題が発生しないことがわかったので、本番の読み取りトラフィックを全てAuroraレプリカで処理する構成にしました。これは、移行当日のオペレーションを少しでも少なくするという意図があります。 Route53で振り分けるエンドポイントとしては、インスタンスのエンドポイントではなく、Auroraクラスタの[cluster endpoint]と[reader endpoint]に50%ずつの割合で振り分けました。

f:id:nagais:20180828130123j:plain

④サービス用途以外のレプリカDBを、Auroraをマスターとするbinlogレプリにて作成

コネヒトでは、サービス用途以外でもレプリカDBを使っています。 ですが、Auroraレプリカは、起動時点でAuroraクラスタの[reader endpoint]のメンバになります。[reader endpoint]は、アプリケーションからの読み取りトラフィックを処理させるエンドポイントに使っているため、Auroraレプリカをサービス以外の用途で使うことは仕組み上出来ません。

この状況を回避するために、Auroraライターからbinlogレプリを手動で組み、RDS for MySQLのインスタンスを運用する構成にしました。2台必要でしたので、Auroraライターの2スレッドとbinlogを有効にすることのオーバーヘッドが懸念されましたが、特に負荷的な問題はありませんでした。

本当は、複数の[reader endpoint]を作り用途毎に分散出来ると最高なのですが、現時点ではそのような機能はありませんでした。(先にも出来るかわからないですがほしい)

移行方法については、下記公式リファレンスに丁寧にまとめられておりこちらを参考に特につまづきポイントなく行えました。(通常のMySQLの非同期レプリとほぼ同じ手順です)

Aurora と MySQL との間、または Aurora と別の Aurora DB クラスターとの間のレプリケーション - Amazon Aurora

このステップが終わった段階で、残るはアプリケーションの書込トラフィックを司る、MySQLマスターをAuroraに切り替える作業だけとなりました。

f:id:nagais:20180828130137j:plain

⑤書込トラフィックのAuroraへの切替

いよいよ移行当日です。 当日は、サービスのトラフィックが最も少ない時間を狙ってメンテナンス通知を出して移行作業を行いました。

1. MySQLへの書込トラフィックを遮断

まず、MySQLマスタへの書込トラフィックを遮断しました。

  • route53で、書込エンドポイントの向け先をAuroraクラスタの[reader endpoint]に変更
  • セキュリティグループを編集し、MySQLマスタへの3306通信を遮断
2. 最終書込のAuroraへのレプリケーション確認

Auroraライターで、レプリカラグが0になり全てのMySQLマスタのトランザクションが伝搬されたことを確認。

3. Auroraマスター昇格

Auroraライターを昇格させて、Auroraクラスタのロールをマスターに変更します(1分かからないくらい)

4. 書込トラフィックをAuroraへ切替

route53で、書込エンドポイントの向け先をAuroraクラスタの[cluster endpoint]に変更

これで、切替は済んだので、アプリケーションの試験やエラーのウォッチに入り、全ての項目をパスした段階でMySQLマスタはスナップショットを取得した後、削除しました。

※VPCフローログを使って、MySQLマスターへのMySQL通信がDenyされていることを気軽に確認出来るのも作業短縮に大いに役立ちました。

当日は3分強のダウンタイムでAurora移行が実現出来ました。

※段階的に検証を重ねていたので、まぁないだろうとは思いつつ、もちろんロールバックプランも用意しました。この形式だと、MySQLマスタからレプリを全て組み直し、Auroraライターに書き込まれた差分データを確認してMySQLに書き戻すような地獄のような作業です。。。

f:id:nagais:20180828130223j:plain

RDS for MySQLから移行する時の注意点

  • パラメータグループが、クラスタとインスタンスに別れているので注意

RDS for MySQLからの移行だったので、既存のパラメータグループをAurora用のパラメータグループにコピーする必要がありました。その際に、Auroraのパラメータグループには、クラスタパラメータグループとインスタンスパラメータグループに分かれており、項目毎に分割されているので注意が必要です。

こちらに詳しくまとまっています。

Amazon Aurora MySQLリファレンス - Amazon Aurora

  • バックトラックは、binlogレプリを組んでいる場合は使えない。

Auroraのうれしい機能であるバックトラック機能(オペミス時等に巻き戻しが可能)ですが、binlogレプリを組んでいると使えません。仕組み的にそれはそうだなと思うのですが、binlogレプリは、機能別リーダエンドポイント的なものが出来れば捨てられるので進化に期待だなというところです。(バックトラックは、クラスタ作成時しか有効に出来なかったはずなので、この先導入は難しいですが。。)

Auroraへの要望

移行や検証している中で、Auroraに今後出来たら更に楽になるなと思うところがあったので書き留めておきます。

複数のリーダエンドポイントを設けたい

再三書いてはいますが、役割別にリーダエンドポイントを作れるとAuroraレプリカの自由度が増すので出来たらうれしいなと思っています。

binlogレプリだと、レプリケーションのステータスを自前で監視する必要が出てきますが、全てAuroraに出来ればそれもCloudWatchでまかなえるので。

新規レプリカ作成時に、別レプリカからキャッシュをロードしてくれるとうれしい

Auroraはキャッシュ層をDBエンジンと分離してもつアーキテクチャなので、インスタンス再起動時にシャットダウン前のページキャッシュを保存し、再起動時にそれをロードしてくれるため、俗にいうあたため行為(キャッシュ作り)が不要です。

Aurora自体、Auto Scalling機能をもっており、新規レプリカ作成時も何らかの方法でキャッシュをロードするような仕組みがあると更にDB運用が楽になると思っています。

さいごに

メインDBのAurora化というインパクトの大きな緊張感ある作業でしたが、AWSが提供してくれている機能をうまく使うことで、作業を分割しながらリスクヘッジして進めることが出来ました。特に、MySQL5.6互換であることとAuroraリードレプリカの存在が大きかったです。 何もなさすぎて本当に大丈夫なのか?というくらい、何のエラーや障害もなくメインDBのAurora化が終わり現在も元気に動いてます。

Auroraにすることで、性能面・運用面・コスト面(構成次第)で様々なメリットが享受出来、移行自体もMySQL5.6を使っている環境であればそれほど大変ではないのでおすすめです。 このブログがAurora移行を検討している方の何らかの助けになれると幸いです。

コネヒトではコンテナ周りの基盤を整備したりサービス改善を行うエンジニアを募集しています。 少しでも興味もたれた方は、是非気軽にオフィスに遊びにきていただけるとうれしいです。

www.wantedly.com