[アップデート] AWS Fault Injection Simulator で EBS の I/O 停止アクションが利用出来るようになりました

2023.01.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いわさです。

本日のアップデートで AWS FIS (Fault Injection Simulator) で新たに EBS に関する障害を発生させることが出来るようになりました。
What's new のアップデート情報は以下となります。

ちょっと使ってみたのですが、単純に EC2 の停止アクションとは違って、EC2 が起動されたまま EBS だけ障害させることでアプリケーションレイヤーの復旧性能の確認に使えそうなのでちょっとおもしろそうです。

少し使ってみたので紹介します。

停止時間と対象リソースを指定するだけ

FIS は非常に利用が簡単で複雑な設定ファイルなどなくアクションとリソースを指定するだけで利用することが出来ます。
EBS の I/O 停止も同様でアクションにaws:ebs:pause-volume-ioを指定して停止時間と対象リソースを指定するだけです。

停止時間は最短 1 秒、最長で 12 時間を指定出来ます。
ここで指定した時間が実際の EBS の I/O 停止時間になります。
実験の初期化や終了処理など含めると実際の実験に必要な時間はここで設定した時間+αということになります。

実行中の挙動

EBS がアタッチされている EC2 インスタンスを作成し、早速実験を開始します。

実験が Running になると EBS の I/O が停止します。
ただし、ボリュームのステータスチェックは 5 分ごとに自動的にチェックされているようなので、ステータス上少しタイムラグがあります。

また、マネジメントコンソール上は I/O パフォーマンスが「停止」ステータスとなりボリュームのステータスも「障害」となりますが、I/O ステータス自体は「有効」のままでした。

さらに、EC2 のルートボリュームの I/O が停止したとしても EC2 のインスタンスステータスチェックについては正常のままでした。
アプリレイヤーからどう見えるのかは後述しますが、実際には SSM などを始め EC2 へアクセス出来ない状態にはなるのですが。

ちなみに、今回学んだのですがボリュームステータスチェック自体は io1, io2, gp3 の場合のみ利用可能で、それ以外の場合は利用出来ません。
そのため、gp2 に対して今回のアクションを使ってもボリュームステータス上は「OK」となります。
ただし、gp2 だと今回の FIS のアクションが使えないというわけではなく I/O 自体は gp2 だとしても止まります。あくまでもステータス上は正常なままということです。

ボリュームステータスチェックについて詳しくは以下の公式ドキュメントもご確認ください。

終了後

実験終了後はすぐに I/O の停止が解除されます。

ボリュームステータスは停止時と同様にタイムラグがあります。

アプリの例外処理の確認にも使える

EBS のステータスが I/O 停止時と同様のものになっているだけなのか、それとも実際に I/O が停止しているのかは少し気になるところだと思います。
そこで、以下を参考に ioping の実行中に FIS で停止を行ってみました。

[ec2-user@ip-172-31-26-137 ioping]$ ./ioping -v
ioping 1.3.3.g9471fed
[ec2-user@ip-172-31-26-137 ioping]$ idblk
bash: idblk: command not found
[ec2-user@ip-172-31-26-137 ioping]$ lsblk
NAME          MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1       259:0    0   8G  0 disk
├─nvme0n1p1   259:1    0   8G  0 part /
└─nvme0n1p128 259:2    0   1M  0 part
nvme1n1       259:3    0  20G  0 disk /data

上記記事を参考に Amazon Linux 2 へ ioping を導入済みです。
追加 EBS ボリュームが/dataにマウントしてあります。
このあたりは以下の記事を参考にさせてもらいました。

あとは以下のように ioping を /data に対して実行した状態で FIS で停止し観察してみます。
実験が runnning になるタイミングで以下の状態で ioping の出力が停止しました。

[ec2-user@ip-172-31-26-137 ioping]$ sudo ./ioping /data/
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=1 time=753.1 us (warmup)
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=2 time=789.1 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=3 time=663.8 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=4 time=264.9 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=5 time=1.10 ms

:

4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=61 time=532.7 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=62 time=441.3 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=63 time=387.3 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=64 time=638.7 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=65 time=731.8 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=66 time=402.6 us

数分待ってから実験を停止してみます。

すると次のように ioping の出力がすぐに再開されました。
そして、request=67の時間は停止していたため時間が3.20 minになっています。

[ec2-user@ip-172-31-26-137 ioping]$ sudo ./ioping /data/
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=1 time=753.1 us (warmup)
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=2 time=789.1 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=3 time=663.8 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=4 time=264.9 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=5 time=1.10 ms

:

4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=61 time=532.7 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=62 time=441.3 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=63 time=387.3 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=64 time=638.7 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=65 time=731.8 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=66 time=402.6 us
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=67 time=3.20 min (slow)
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=68 time=5.95 ms (fast)
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=69 time=384.3 us (fast)
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=70 time=489.0 us (fast)
4 KiB <<< /data/ (xfs /dev/nvme1n1 20.0 GiB): request=71 time=534.1 us (fast)

この検証から EBS のステータスだけが変わっているだけなく、実験によって実際に I/O が停止していることが確認出来ました。

注意事項

今回のアクションを利用するにあたっていくつか注意事項があります。

ターゲット内のアベイラビリティゾーンは同じものを指定する必要がある

複数のインスタンスを対象とする場合に AZ (アベイラビリティゾーン) が分散することがあると思いますが、1 つのターゲットに指定出来る EBS ボリュームは全て同じ AZ である必要がありますので注意が必要です。
実験テンプレートの作成自体が出来ません。

複数を同時に停止したい場合は次のようにアクションとターゲットを AZ ごとに分けて用意してやると実行することが可能です。

Nitro System 上のインスタンスにアタッチされている必要がある

これはアクションの仕様・制限事項になりますが、Nitro System 上のインスタンスにアタッチされた EBS ボリュームが対象となります。
そのため、例えば t2.micro などで作成した EC2 インスタンスにアタッチされた EBS ボリュームを停止しようとすると、実験テンプレートの作成は成功しますが、実験が失敗してしまいます。

実験は失敗しました。
Unable to start Pause Volume IO. Target volumes must be attached to an instance type based on the Nitro system. VolumeId(s): [vol-0ac9460d7cd048fec]

Nitro System で利用可能なインスタンスタイプについては以下をご確認ください。

さいごに

AWS Fault Injection Simulator で EBS の I/O 停止アクションが利用出来るようになったので少し使ってみました。

EC2 を停止せずに EBS だけ障害発生させることが出来るので、ASG など使うようなインフラレイヤーではなく、復旧処理やリトライ処理などアプリケーションレイヤーでの耐障害性のテストにも使えそうなアクションでとても良いですね。

FIS の最初のころはインスタンスを停止するくらいで、FIS じゃなくても出来るよねみたいに思うところも少しあったのですが、先日のネットワーク障害アクションだったり今回のアクションのように、より内部の障害を発生させることが出来るようになってきて良い感じに進化しているなと思いました。

ちなみに、Nitro については今後旧世代インスタンスのサポートによって今回のアクションのサポート範囲も広がるのか気になるところです。