[PR] あなたが Kindle で読みたいその本、Kindle に対応したら Twitter でお知らせします。

Amazon RDS のメンテナンスにどう立ち向かうべきか

Posted on

RDS for PostgreSQL にシステムアップデートがやってきましたね。

今回のアップデートは必須なので猶予期間の間に必ず適用する必要があります。 Multi-AZ 構成にしていれば自動的にフェイルオーバーしますが、60 〜 120 秒のダウンタイムは避けれません。

プロダクション環境の RDS で同様のメンテナンスは何度か経験しましたが、オフタイム(主に休日)にメンテナンスを計画しその度にエンジニアが待機していました。当日はメンテナンスに切り替えて見守るだけなのですが、メンテナンス告知など諸々の調整や休日出勤でそれなりの保守コストがかかっています。お客様にも迷惑をかけるしエンジニアにも負担を強いていたのです。

この機会に、実装やアーキテクチャの改善で RDS のダウンタイムを回避(もしくは緩和)できないか考えてみました。ダウンタイムに柔軟に対応できれば、メンテナンス時だけでなく障害にも強くなるはずです。

なお、データベースエンジンは問いませんが Multi-AZ 構成が前提です。あと、Oracle Database や SQL Server のような商用製品は使ったことがないので、もしかするともっとスマートな解決方法があるかもしれません。もっといい方法をご存知の方は、ぜひ教えてください :-)

参照系はリードレプリカに逃す

フェイルオーバーしている間はプライマリとスタンバイの両方にアクセスできないので、参照系のクエリはリードレプリカに逃がします。

通常はすべてのクエリをプライマリに投げておき、プライマリが参照できないときはリードレプリカにリトライするという処理が必要です。すでにリードレプリカを使っているのであればアプリケーションに手を加える必要はないでしょう。

注意点としては、リードレプリカへのレプリケショーンは遅延する可能性があるので、プライマリに投げた直前の更新系クエリが必ず反映されている保証はありません。

更新系は難しい

参照系は割と簡単に対応できますが、問題になるのは更新系のクエリです。当然ですがリードレプリカは更新系には使えません。

参照系は多少エラーになってもリトライすれば解決しますが、更新系を適当に扱ってしまうと重大な事故につながります。それに加えて更新系はプライマリにしか投げれないので、フェイルオーバーしている間の更新系クエリをうまくハンドリングする必要があります。ですが、言うは易く行うは難しで実装するのはかなり難しいです。

安直に実装するならば、フェイルオーバーが完了するまでリトライするのが簡単でしょう。ただし、リトライ間隔や回数、同期処理か非同期処理、さらに非同期処理の場合は排他制御や結果通知など考慮すべきことが多すぎます。

やはりフェイルオーバーしている間は ユーザーからの更新クエリを受け付けないのが鉄則 です。ユーザーにはエラーではなく「数分後に再度お試しください」といったリトライを促すようなメッセージを出すと良いでしょう。

更新系の停止時間を最小化する

アプリケーションをメンテナンスに切り替えることなく、自動的に更新系を停止するには AWS の機能を組み合わせます。 RDS にはイベント通知機能があり、Amazon SNS 経由でフェイルオーバーの通知を受け取れます。さらに SNS は Lambda と連携できます。

これらを組み合わせると、

  1. メンテナンスウィンドウの開始直前に更新停止フラグを立てる
  2. フェイルオーバーが開始される(60 〜 120 秒)
  3. フェイルオーバーの完了通知を SNS で受けて Lambda ファンクションを実行する
  4. Lambda ファンクションが更新停止フラグを下げる

といったことが全自動で実現でき、かつ更新系を停止する時間を最小化できます。更新停止フラグをチェックするという処理は必要ですが、DAO に少し手を加えれば実現できるでしょう。

コネクションプーリングは必要か?

コネクションプーリングを使っている場合は、フェイルオーバーしたときにコネクションが切断されてエラーが発生するかもしれません。自分たちが一番困っているのは実はこの部分だったりします。

コネクションプーリングには 2 つの役割があります。

  • 接続に必要とされるオーバーヘッドを減らして接続コストを下げる
  • 接続を使いまわすことで同時接続本数を節約する

自分たちは主に 1 つ目の理由でコネクションプーリングを使っていますが、最近はサーバの性能も向上しているので見直す価値はありそうです。コネクションプーリングは賛否両論ありますが、各サーバを密に結合しない方が運用しやすいのは間違いないです。

まとめ

どの方法を選んだとして、コスト増とアプリケーションの変更は必要だということがわかりました。 RDS のメンテナンスは年に数回しかないので、かけるコストと得られるメリットを天秤にかけることになりそうです。

とはいえ、エンジニアが手作業でメンテナンスに切り替えるのはイケてないので、まずは Lambda の Scheduled Event で自動化してみたいと思います。