第6回のオンライン輪読会に備えて読んだ内容を自分なりにまとめておく。
今回の記事はこちら。
[期待/予想する内容]
この記事の目次は次のとおりである。
- はじめに
- 単一マシンのフォールバック
- 分散フォールバック
- Amazonがフォールバックを回避する方法
- まとめ
目次がシンプル……!
「単一マシンのフォールバック」……そもそもフォールバックという言葉がどういうことを指しているのか、自分は曖昧にしか理解できていない。縮退運転だから、ロードバランサの裏に複数あるリージョンを減らしてサービス提供を継続する、というようなイメージでいる。単一マシンで障害があったら、縮退できないから、別マシンをスタンバイさせておくとか、そういう話だろうか。
「分散フォールバック」……分散システムの場合は、それこそリージョン切り離しとか、一部機能を停止するとかだろうか。
「Amazonがフォールバックを回避する方法」……Amazonが、とうたっている以上、これまでの記事にもあったようなベストプラクティスが掲載されている、はず。
内容としては、やはりここが一番重要そう。例によって、実践できるかは別だけど。
[記事の要約]
次に、実際に記事を読んだ内容を箇条書きでまとめる。
はじめに
- 重大な障害を回避する方法
- 1)再試行:直後に、または時間をおいて、繰り返す
- 2)積極的な再試行:並列して実行し、最初の結果を利用する
- 3)フェイルオーバー:別のエンドポイントに、可能なら並列で処理を実行する
- 4)フォールバック:同じ結果を得るための異なるメカニズムを利用する
- Amazonではフォールバックをほとんど使わない
- フォールバック戦略が多くの問題を引き起こすから
単一マシンのフォールバック
- C言語でmallocに失敗した場合のエラーハンドリングを考える
- mallocの失敗はメモリ不足、マシンのクラッシュ可能性あり
- なんとかするためにmalloc2を実装するとどうなるか?
- そもそもテストが困難
- 本番環境を正確に再現できない
- フォールバック自体が失敗する可能性もあり、障害を完全には排除できない
- 使用頻度の低いフォールバック戦略よりも、本来のコードの信頼性を高めることの方が重要
- フォールバックは顧客の問題を悪化させる可能性も
- malloc2がSSDにアクセスしてメモリ確保するとする
- mallocよりも当然アプリケーションが低速になる
- そもそもメモリ不足なのでマシンも低速である
- SSDを他サブシステムと奪い合うなど、予測不能な負荷の可能性
- 単一マシンであれば、mallocに失敗したらアプリをクラッシュさせるのが一番
- エラー時も動作する必要があるなら、最初からヒープメモリを割当、malloc依存を排除する
- 本番サーバーのデーモンの監視
- CPUバーストを監視するEC2デーモン
分散フォールバック
- サービス=分散システムは単一マシンよりも高可用性が期待される
- そのため、フォールバックを実装する必要があるが、重大な障害以上の問題がある
- 分散フォールバックはテストが難しい
- 分散フォールバック自体が失敗する可能性
- 分散フォールバックが障害を悪化させる可能性
- 分散フォールバックはリスクに見合わない
- 分散フォールバックに潜在的なバグがある
- Amazonでの配送速度表示機能のフォールバックと障害
- DBから直接取得するしかなかった
- なので、DBをフォールバックとして、インラインキャッシュを実装した
- キャッシュ障害によりDBにThundering Herdが発生
- Webサイトが完全に停止
- 同じDBを利用していた配送センターも停止
- フォールバックが存在したことで、Webサイトの部分停止が全体停止に、さらに配送ネットワーク全体へ波及
Amazonがフォールバックを回避する方法
- 非フォールバックケースの信頼性を向上させる
- フォールバックではなくより可用性の高いものに投資すべし
- 例)DynamoDBを使う
- 呼び出す側にエラーを処理させる
- データを積極的にプッシュする
- サービスに必要なデータをローカルに置いておく
- 例)EC2インスタンスにIAM認証情報をプッシュしている
- フォールバックをフェイルオーバに変換する
- 本番環境でごく稀にだけ使われるフォールバックはダメ
- 同じロジックをフェイルオーバとして、並行稼働させることが重要
- 再試行とタイムアウトがフォールバックにならないようにする
- 再試行とタイムアウトはパケットロスなどの偶発的な障害に強い
- しかし、滅多に起きないのでテストされずに本番障害時に活躍することも
- 常に積極的な再試行を利用する(並列要求)
- 例)DynamoDBのようなQuorumを利用した読み取り・書き込み
- 常に再試行が並列で実行されるので再試行による負荷増加はない
まとめ
- フォールバックは有効性のテストが難しいので避けている
- データをプッシュするなどでプライマリパスの可用性を高めるべき
- どうしてもフォールバックが必要な場合は頻繁に実行して信頼性を高めるべし
[予想のふりかえりなど]
フォールバックで分散システムの障害を乗り切るぜ、的なノリかと思っていたが、「フォールバックは避けるべき」との論調で少し驚いた。
驚いたが、テストの難しさや影響の読めなさを理解すると、確かに避けるべきであると理解できる気がする。そもそもタイトルで「回避」とあるのはそういうことか。
どういう風にフォールバックするべきか、だけではなく、そもそもフォールバックしなくて済むようにという視点でベストプラクティスが語られているのが興味深かった。その流れで、IAMロールとEC2インスタンスの意外な関係を知ることができたのも勉強になった。
並列リクエストを利用して、再試行を普段から実践しておくというのは、DynamoDBの内部実装としてどこかの資料で見たことはあった。こういう風に可用性を高めることに繋がっていたのか、と再認識できた。
[まとめ]
- 「The Amazon Builder's Library」の『分散システムでのフォールバックの回避』を読んだ
- テストできているか?という観点で障害対応を考える習慣を見習いたい
- コードの正常系で通信が必要のないように外部からデータをプッシュしてローカルに貯めておくという手法を学んだ(IAMロール -> EC2インスタンス)
これで6/13記事を読んだことになる。およそ半分。
引き続きAmazon Builder's Library読んでいくぞ。