稼働中の ElastiCache Redis にサービスの更新(engine-update)の通知があったので手動で適用をしました。メンテナンスのヘルプ - Amazon ElastiCache | AWS によると数秒のダウンタイムが発生するとのことですが、どのくらいサービスがダウンするのか redis-cli を使って調べてみたので記録を残します。
目次
ElastiCache Redis の環境
- モード:Redis
- ノードのタイプ:cache.t3.micro
- エンジンのバージョン 互換性:6.0.5
- シャード:1
- ノードの数:2
- マルチ AZ:enabled
- 自動フェイルオーバー:enabled
- データ量:およそ 50 MB
検証用の環境
- Amazon ECS-optimized Amazon Linux 2 × 2 台
- Docker 19.03.13-ce
- redis:6.0.5-alpine Docker イメージ
1 台目
ターミナルウィンドウを 2 個立ち上げ、それぞれのウィンドウで 1 台目の Amazon Linux にログインし Docker コンテナにログインします。
docker run --rm -it redis:6.0.5-alpine ash
読み書きのコマンドを実行して、更新中にエラーが出るかどうかを確認します。
ウィンドウ 1 では、1 秒に 1 回、数字を 1 ずつ増やしながら書き込み。
redis-cli -h redis-primary-endpoint set mykey1 "1"
redis-cli -h redis-primary-endpoint -i 1 -r 3600 incr mykey1
ウィンドウ 2 では、1 秒に 1 回、上記で書き込んだキーを読み取り。
redis-cli -h redis-primary-endpoint -i 1 -r 3600 get mykey1
2 台目
ターミナルウィンドウを追加で 2 個立ち上げ、2 台目の Amazon Linux でコンテナにログインします。それぞれのウィンドウで以下のコマンドを実行します。
ウィンドウ 3 では、ループしながら 1 秒に 1 回、数字を 1 ずつ増やしながら別のキーに書き込み。
for i in $(seq 1 3600); do
redis-cli -h redis-primary-endpoint set mykey2 ${i}
sleep 1
done
ウィンドウ 4 では、ループしながら 1 秒に 1 回、上記のキーを読み取り。
while [ true ]; do
redis-cli -h redis-primary-endpoint get mykey2
sleep 1
done
サービス更新の様子
サービス更新をする前に前述の 4 個のスクリプトを流しておきます。
サービス更新を開始すると、サービスの更新ステータスの画面の「ステータスを更新」が waiting-to-start
になります。

サービス更新ステータスのクラスター名のリンクをクリックすると、ノードの「ステータスを更新」が waiting-to-start
になっているのも確認できます。

しばらくして、ノードの末尾 002 (レプリカ)が in-progress
になりました。この後順番に見ていきますが、先にレプリカから更新が行われ、レプリカの更新後に自動でフェイルオーバーしてレプリカとプライマリが入れ替わります。

数分後、ノードの末尾 002 (レプリカ)が complete
になりました。

さらに数分後、ノードの末尾 001 (プライマリ)が in-progress
になりました。

クラスタのステータスも modifying
になりました。更新が終わったレプリカをプライマリに昇格させる処理に入りました。

1 台目の書き込みコマンドのエラー停止
この後、1 台目のターミナルウィンドウに変化が。書き込みをしているコマンドがエラーで止まりました。
/data # redis-cli -h redis-primary-endpoint -i 1 -r 3600 incr mykey1
(integer) 1
(integer) 2
...
(integer) 1296
(integer) 1297
(error) READONLY You can't write against a read only replica.
Error: Server closed the connection
/data #
1 台目で読み込みをしているターミナルウィンドウは書き込みが止まった後 30 秒ほど 2797 の数字を表示し、その後エラーが表示され応答待ちの状態になりました。
/data # redis-cli -h redis-primary-endpoint -i 1 -r 3600 get mykey1
"1"
"2"
...
"1296"
"1297"
"1297"
... (30回ほど続く)
"1297"
"1297"
(error) LOADING Redis is loading the dataset in memory
エラーで止まったターミナルで、書き込みのコマンドを再実行。
/data # redis-cli -h redis-primary-endpoint -i 1 -r 3600 incr mykey1
(integer) 1298
(integer) 1299
応答待ちだった読み込みコマンドを実行していたターミナルは、しばらくして数字が飛んだ状態で再開しました。
/data # redis-cli -h redis-primary-endpoint -i 1 -r 3600 get mykey1
"1"
"2"
...
"1297"
"1297"
(error) LOADING Redis is loading the dataset in memory
"1324"
"1325"
2 台目の書き込みコマンドはエラーなし
2 台目の検証マシンで流していたコマンドはエラーを検出できませんでした。ダウンタイムが 1 秒より短かったのか、接続待ちの状態になっていたか、はっきりしません。コマンドの実行時間を出すようにしておけばよかったです。
for i in $(seq 1 3600); do
redis-cli -h redis-primary-endpoint set mykey2 ${i}
sleep 1
done
OK
OK
OK
while [ true ]; do
redis-cli -h redis-primary-endpoint get mykey2
sleep 1
done
"1296"
"1297"
"1299"
"1299"
"1301"
フェイルオーバーのその後
その後は特にエラーになることもなく「ステータスを更新」が complete
になり、更新が完了しました。

クラスタのステータスも available
になりました。

ノードのステータスも available
です。末尾 002 が primary
に、001 が replica
になっていることも確認できます。

まとめ
- 今回は準備不足でダウンタイムは計測できず
- メンテナンスのヘルプ - Amazon ElastiCache | AWS ではダウンタイムは数秒と記載あり
- 読み書きエラーは確認できたので、ダウンタイムがあるものとしてアプリケーション側で対処しておく必要あり
うまくダウンタイムを測ることができず、ハッキリしない結果になってしまいました。ただし書き込みでエラーは発生したので、ダウンタイムはあるものとして、アプリケーション側でエラーが起きても問題ない作りにしておく必要はありそうです。
またサービス更新の機会があったら再挑戦して記事を更新します。