パブリッククラウドの大規模ゾーン障害について考える

先日AWSで発生した大規模ゾーン障害について考えてみました。

今までは、パブリッククラウドでは下記対応すれば、可用性が担保できると思ってました。

- リージョン内は、Multi-AZ構成で冗長化
- リージョン間は、別リージョンで迅速にサービスが復旧できるようにDR対策

ところが今回の障害でどうもそうでもないような気がしてきました。
Multi-AZ構成ではインスタンス障害やインスタンスへの接続障害がトリガーとなって、自動縮退・自動復旧しますが
ゾーン障害が直接のトリガーとなる訳ではありません。
「ゾーン全体で中途半端に接続障害が発生した場合はどうなるのだろう」という疑問を解消すべく考えてみることにしました。

# 考察内容

そこで以下の状況が発生した場合どのような対応ができるか、考察したいと思います。

- １つのゾーンで10%のトラフィックがエラーになる
- ヘルスチェックに引っかからないため、自動縮退・自動復旧しない

注) 上記想定は、実際に発生した障害と同じという訳ではありません。

# 1. ゾーン障害とMulti-AZの有効性

今回の障害が発生するまでは、ゾーン障害というと
「地震や火災でデータセンターが壊滅的な状態になる」
ようなイメージを持っていました。
Multi-AZ構成であれば、正常なゾーンに縮退しサービスを継続することができます。
もちろん、特定のインスタンス障害の場合でも、Multi-AZ構成は効果があります。

#### Multi-AZ構成：正常時
正常時は2ゾーンに冗長化されています。
![green.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/6b774fca-d400-a6cf-fb8d-8eed908c105c.png)

#### Multi-AZ構成：縮退時
ゾーン障害時またはインスタンス障害時は正常なゾーンに縮退します。
![zone_failure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/be19b5ae-ca13-5596-c0a4-e75a5787bcbe.png)



ところが、今回発生した障害は


- EC2とEBSのパフォーマンス劣化
    - 当初はEC2の接続障害と説明
- RDSの接続障害

とのことでした。
ここでは接続障害に注目して、特定のゾーンで10%のトラフィックがエラーになるような
接続障害が発生したとします。

#### Multi-AZ構成：特定のゾーンで10%位のトラフィックでエラー
3回中3回エラーになるかチェックするようなヘルスチェックだとヘルスチェックをすり抜けて、縮退・自動復旧しません。
全体で 10 / 2 = 5%のトラフィックがエラーになってしまいます。

![zone_failure2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/94b79a02-ec9b-5f6b-6bfa-f080305a74d8.png)


#### Multi-AZ構成：両方のゾーンで10%のトラフィックでエラー
両方のゾーンで10%のトラフィックがエラーになるとすると、そもそもゾーンの縮退ができません。

![zone_failure31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/893ede1b-e825-42c2-3dca-e5ea711e3ad3.png)


# 2. 対応策の考察

上記を踏まえ、以下の障害が発生した時の対応策について考察します。

- １つのゾーンで10%のトラフィックがエラーになる
- ヘルスチェックに引っかからないため、自動縮退・自動復旧しない

## 1) アプリで対応

以下のような対応を実装して、多少遅延はあるものサービスが継続できる、一部機能が提供できなくてもサービスは停止しないようにするのがあるべき論だと思います。

- exponential backoffを実装する
- circuit breakerを実装する

AWSは昔からexponential backoffの実装を啓蒙し続けているように思えるのですが、個人的な感覚ではまだまだ実装されてないシステムが多い感じがします。

ただMulti-AZやヘルスチェックと組み合わせないでアプリだけで対応しようとすると、ヘルスチェックに引っかかるレベルのネットワーク・インスタンス障害が発生してもcircuit breakerでブロックするまで、トラフィックが流れてしまいます。
ですのでアプリで対応する場合も、Multi-AZとの組み合わせは必須だと考えます。

次からはインフラレイヤーでの対応策を検討したいと思います。

## 2) Multi-AZ

上で述べたとおり、10%のトラフィックがエラーになる状況では(設定次第ではありますが)

- ヘルスチェックをすり抜けるため、状況は変わらない。
- ヘルスチェックにかかった場合でも、縮退・復旧・縮退・復旧・・・を繰り返す可能性がある

ようになってしまいます。
また、縮退・復旧したとしても復旧先のゾーンが障害中のゾーンだとすると、同じことの繰り返しになります。

この状況をインフラレイヤーだけで回避するためには、「**ゾーン障害をトリガーにして、ゾーンごと縮退させる**」ことが必要だと考えます。
Multi-AZの本質は、「インスタンス障害をトリガーにしてインスタンス単位で縮退させることによりゾーン障害に対応する」ことではないかと思っているのですが、自分の知る限り「**ゾーン障害をトリガーにして**」の部分は標準機能として提供されていないため、その部分を自前で実装する必要があると思っています。
ただ、インフラレイヤーを抽象化したLambdaやFargateは、そもそもそのような実装を組み入れること自体困難かつナンセンスです。
IaaSやコンテナにおけるゾーン全体の縮退の実現性は別の機会に検討したいと思っています。

#### RDSの例
RDSのMulti-AZはゾーン障害に対応できますが、2インスタンスが別ゾーンにあって、インスタンス障害により別ゾーンのインスタンスにフェイルオーバするため、結果ゾーン障害に対応できているとも考えられます。
また複数ゾーンにそれぞれRDSのリードレプリカが複数ある構成を考えた場合、インスタンス単位で縮退した結果としてゾーン障害に対応できることはあっても、ゾーン障害をトリガーにして対象ゾーンの全てのインスタンスを縮退するといった機能は標準では提供されていません。

## 3) 3ゾーン冗長化

Multi-AZと状況は変わりませんが、エラーが3ゾーンに分散される分全体のエラー率は下がる点が、Multi-AZより若干優れていると考えられます。

![3zone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/3948ce2d-d85d-2b41-84cf-a8a9c0a6a399.png)

またAuroraのストレージレイヤーは3ゾーン6箇所に冗長化して多数決をとるような仕組みになっていますが、まさに今回のような障害のためにあるような仕組みだと言えます。
Auroraの後発でリリースされたAmazon NeptuneやAmazon DocumentDBも同じようなストレージレイヤーを備えていますが、今後このような耐障害性の高いサービスが増えていくことが期待できます。

ただ、EC2やECSにAuroraのストレージレイヤーのような多数決による冗長化を導入するのはかなり無理があるので、現状は1) アプリで対応で述べたような対応と組み合わせるしかないと考えます。

## 4) リージョン間DR

ゾーン障害を含むリージョンから別リージョンへフェイルオーバするリージョン間DRであれば、このような障害に完全に対応可能です。
フェイルオーバーのダウンタイムとデータの欠損を考慮しなければならない所がデメリットですが、逆にダウンタイムとデータの欠損を最小化(またはゼロ)にするシステムを作るところが面白い所ではないでしょうか。

## 5) 他クラウドへ移行

こういった大規模障害が発生すると、他クラウドに移行した方が良いのではといった考えが浮かんでくるかもしれませんが、仮にAzureやGCPへ移行してもAからBへ移しただけで何も状況は変わりません。それよりもこういった障害をクラウドの特性と捉えて、前向きに対応を検討するべきだと考えます。
ただ、AWSの補完として、DR先やクラウド間冗長化のために他クラウドを利用することを検討するのはアリだと思います。

# 3. 結論

以下の障害が発生した時の対応について、考察した結果をまとめます。

#### 想定する障害

- １つのゾーンで10%のトラフィックがエラーになる
- ヘルスチェックに引っかからないため、自動縮退・自動復旧しない

#### 対応案と効果

|対応案|上記障害に対応できるか|補足|デメリット|
|---|:---:|---|---|
|アプリ対応|○| |ヘルスチェックに引っかかるレベルの障害もアプリ対応になる|
|Multi-AZ|△|エラーの分散は可能|縮退できない|
|3ゾーン冗長化|△+|Multi-AZよりもエラーの分散は可能|縮退できない|
|アプリ対応+Multi-AZ|◎| | |
|リージョン間DR|◎| |フェイルオーバのダウンタイム|

アプリ対応+Multi-AZが王道だと考えます。素直にあるべき論に従い正しい実装することが、結局一番の近道ではないかと思います。
またリージョン間DRも合わせて実装し、リージョン障害だけでなくゾーン障害時でも利用できるように常に準備しておけばさらに良い対策だと考えます。

ただ、上記に合わせてゾーン全体の縮退が容易にできる対応策を準備しておいても良いのではと感じています。
実現性については別の機会に検討したいと思います。