はじめに
2022月12月時点の動作確認結果を記載したものです。
Amazon RDS for PostgreSQL(以下RDS)を利用して際、フェイルオーバー発生時のダウンタイムについて確認してみました。特にRDSやSQLへコマンドベースで「数十秒から数分のダウンタイムしかありませんでした」というものはありますが、もう少しwebシステムを利用する利用者目線でどうなるのか?を知りたいと思い、検証した結果を記載します。
前提
確認した環境を記載します。
XAMPP: 8.0.25
Apache: 2.4.54(win64)
OS(利用したAMI): Windows_Server-2022-Japanese-Full-Base-2022.11.10
RDS for PostgreSQL:13.7
システム構成図:
結論
今回の条件だと、45秒でフェイルオーバーが完了しました。
+++ログ抜粋+++
2022/12/23 09:27:47 !!!DB接続成功!!!
2022/12/23 09:28:09 ...DBに接続できません...
2022/12/23 09:28:31 ...DBに接続できません...
2022/12/23 09:28:32 !!!DB接続成功!!!
実際の動作
①VPC外に存在しているPCのブラウザからPublicSubnetで動作しているEC2のWebページへアクセスします。
②正常にアクセスできると1秒間隔でPHPでRDSへ接続を行う。以下の画面が1秒間隔でリフレッシュされます。
③RDSを手動フェイルオーバー(RDSの管理画面の[アクション]-[再起動]-[フェイルオーバーで再起動しますか?]にチェックを付けて実行する)を実施します。
④ブラウザ接続されている画面が1秒間隔での更新ができなくなる=フェイルオーバーが発生する。以下のようにブラウザのファビコンが更新中のままになります。
⑤フェイルオーバー発生中に接続できなかった場合、以下の画面になります。
⑥プライマリとセカンダリの切り替わる完了すると1秒間隔での接続が正常に実行可能となります。つまり”②”の動作になります。
⑦フェイルオーバーによりRDSの変更がされた=AZがプライマリとセカンダリで入れ替わっている ことをRDSの管理ページ(以下)から確認可能です。すぐにGUI上に反映されない場合は数分時間をおいてアクセスして確認します。
まとめ
1分以内だとアプリケーション側でのリトライ処理であったり、エラー表示して数分後に接続を促すことでエンドユーザー側へフェイルオーバー発生していることを感じさせることなく利用してもらうことも場合によっては可能かと考えます。
一番の懸念点としては、今回は手動でフェイルオーバーを発生させた点です。RDSが自動的にフェイルオーバーするときはRDSのメンテナンス実施時や、RDSのデータストアやAZ内での障害発生時となるよう*1です。そのようなときは他ユーザーもフェイルオーバーが必要な状態のため今のような時間でフェイルオーバー完了することはない可能性も頭の中に入れておかないといけないと感じました。
*1 詳細は以下公式情報をご確認ください。
Amazon RDS DB インスタンスが再起動、回復、またはフェイルオーバーしたのはなぜですか?
https://aws.amazon.com/jp/premiumsupport/knowledge-center/rds-multi-az-failover-restart/
付録
利用したPHPを貼り付けます。RDSのエンドポイントや接続に利用するための認証情報は利用するものを記載してください。なお、ログはhtdocsフォルダにある”debug.log”に記録するようにしています。
<html>
<head><title>Let's check the database connection</title></head>
<body>
<?php
echo "PostgreSQL接続テスト", PHP_EOL;
echo "</br>";
date_default_timezone_set('Asia/Tokyo');
$link = pg_connect("host=ここにはRDSのエンドポイントを記載します port=5432 user=ユーザー名 password=パスワード");
if (!$link) {
$a =date("Y/m/d H:i:s");
echo $a." ";
echo "... DBに接続できません...";
echo "</br>";
error_log("$a ...DBに接続できません...\n", 3, "./debug.log");
} else {
$a =date("Y/m/d H:i:s");
echo $a." ";
echo "!!!DB接続成功!!!";
echo "</br>";
error_log("$a !!!DB接続成功!!!\n", 3, "./debug.log");
pg_close($link);
}
if(isset($_POST['pause'])){
$a =date("Y/m/d H:i:s");
echo $a." ";
echo "... xxx一時停止しますxxx...";
error_log("$a ... xxx一時停止しますxxx...\n", 3, "./debug.log");
sleep(9999);
}elseif(isset($_POST['restart'])){
$a =date("Y/m/d H:i:s");
echo $a." ";
echo "... xxx再開しますxxx...";
error_log("$a ... xxx再開しますxxx...\n", 3, "./debug.log");
header("Refresh:1");
}
?>
<form action="check_connection.php" method="post">
<input type="submit" name="pause" value="停止" />
<input type="submit" name="restart" value="再開" />
</form></body>
</html>