MTBF の増加 - 可用性およびその他:AWS の分散システムの回復力の理解と向上

MTBF の増加

可用性を向上させる最後の要素は、MTBF の増加です。これは、ソフトウェアとその実行に使用される AWS サービスの両方に当てはまります。

分散システムの MTBF の増加

MTBF を増やす方法の 1 つは、ソフトウェアの欠陥を減らすことです。この方法には、いくつかあります。カスタマーは Amazon CodeGuru Reviewer などのツールを使用して、一般的なエラーを見つけて修正できます。また、ソフトウェアを本番環境にデプロイする前に、包括的なピアコードレビュー、ユニットテスト、統合テスト、リグレッションテスト、および負荷テストを実行する必要があります。テストのコードカバレッジを増やすと、一般的でないコード実行パスでも確実にテストできるようになります。

小さな変更をデプロイすることは、変更の複雑さが軽減され、予期しない結果を防ぐのにも役立ちます。それぞれのアクティビティは、障害が発生する前に欠陥を特定して修正する機会を提供します。

障害を防ぐもう 1 つの方法は、定期的なテストです。カオスエンジニアリングプログラムを実装すると、ワークロードがどのように障害を起こすかをテストしたり、復旧手順を検証したり、本番環境で障害が発生する前に障害モードを見つけて修正するのに役立ちます。カスタマーは、カオスエンジニアリング実験ツールセットの一部として AWS Fault Injection Simulator を使用できます。

分散システムで障害を防ぐもう 1 つの方法は、耐障害性です。フェイルファストモジュール、エクスポネンシャルバックオフとジッターによる再試行、トランザクション、冪等性はすべて、ワークロードの耐障害性に役立つ手法です。

トランザクションは、ACID プロパティに準拠したオペレーションのグループです。その内容は次のとおりです。

  • 不可分性 — すべてのアクションが実行されるか、まったく実行されないかのどちらかです。

  • 整合性 — 各トランザクションは、ワークロードを有効な状態のままにします。

  • 分離性 — トランザクションを並行して実行すると、ワークロードは連続して実行された場合と同じ状態になります。

  • 耐久性 — トランザクションがコミットされると、ワークロードに障害が発生した場合でもその影響はすべて維持されます。

エクスポネンシャルバックオフとジッターによる再試行を行うと、ハイゼンバグ、過負荷、またはその他の条件によって引き起こされる一時的な障害を克服できるようになります。トランザクションが冪等性の場合は、複数回再試行でき、それによる悪影響はありません。

耐障害性のあるハードウェア構成にハイゼンバグが及ぼす影響については、ハイゼンバグがプライマリサブシステムと冗長サブシステムの両方に発生する確率はごくわずかであるため、ほとんど心配する必要はないでしょう。(Jim Gray の「Why Do Computers Stop and What Can Be Done About It? (コンピューターはなぜ停止するのか、そしてそれに対して何ができるのか?)」(1985 年 6 月、Tandem Technical Report 85.7 を参照)。分散システムでは、ソフトウェアで同じ結果を達成することが必要です。

ハイゼンバグが発生したとき、ソフトウェアが不正な操作やエラーをすばやく検出して、再試行できるようにすることが不可欠です。これは、防御的なプログラミングと、入力、中間結果、および出力の検証によって実現されます。また、プロセスは分離されており、他のプロセスと状態を共有しません。

このモジュラー型アプローチを取ることで、障害発生時の影響範囲が限定されます。プロセスの失敗は独立して発生します。プロセスが失敗したとき、ソフトウェアは「プロセスペア」を使用して作業を再試行する必要があります。これにより、失敗したプロセスの処理を新しいプロセスに引き継ぐことができます。ワークロードの信頼性と完全性を維持するには、各オペレーションを ACID トランザクションとして扱う必要があります。

これにより、トランザクションを中止し、加えられた変更をロールバックすることで、ワークロードの状態を損なうことなくプロセスを失敗させることができます。これにより、復旧プロセスは既知の正常な状態からトランザクションを再試行し、正常に再起動できます。このようにして、ソフトウェアはハイゼンバグに対して耐障害性を持たせることができます。

ただし、ボーアバグに対してソフトウェアに耐障害性を持たせることは、現実的ではありません。どのレベルの冗長性でも正しい結果を達成することはできないため、これらの欠陥はワークロードが本番環境に入る前に発見して取り除く必要があります。(Jim Gray の「Why Do Computers Stop and What Can Be Done About It? (コンピューターはなぜ停止するのか、そしてそれに対して何ができるのか?)」(1985 年 6 月、Tandem Technical Report 85.7 を参照)。

MTBF を増やす最後の方法は、障害による影響の範囲を狭めることです。そのための主な方法は、「耐障害性と障害分離」で前述したように、モジュール化による障害分離を使用して障害コンテナを作成することです。障害発生率を下げると、可用性が向上します。AWS はサービスのコントロールプレーンとデータプレーンへの分割、アベイラビリティーゾーン独立性 (AZI)、リージョナル分離セルベースアーキテクチャ、障害を分離するためのシャッフルシャーディングなどの手法を使用します。これらは AWS カスタマーも使用できるパターンです。

例えば、ワークロードによってカスタマーがインフラストラクチャの異なる障害コンテナに配置され、全カスタマーの 5% にサービスが提供されているシナリオについて検討してみましょう。これらの障害コンテナの 1 つで、リクエストの 10% でクライアントのタイムアウトを超えるレイテンシーが増加するイベントが発生しました。このイベントでは、95% のカスタマーがサービスを 100% 利用できました。残りの 5% については、サービスは 90% 利用可能だったようです。この結果、可用性は、100% の顧客に対してリクエストの 10% が失敗するのではなく (90% の可用性)、1 − (5% of customers×10% of their requests) = 99.5% となります。

ルール 11

障害を分離すると、全体的な障害発生率が低下するため、影響範囲が狭まり、ワークロードの MTBF が増加します。

依存関係の MTBF の増加

AWS 依存関係の MTBF を増やす最初の方法は、障害分離を使用することです。多くの AWS サービスは、AZ であるレベルの分離を提供しています。つまり、ある AZ で障害が発生しても、別の AZ のサービスには影響しません。

複数の AZ で冗長 EC2 インスタンスを使用すると、サブシステムの可用性が向上します。AZI は 1 つのリージョン内でスペアリング機能を提供するため、AZI サービスの可用性を高めることができます。

ただし、すべての AWS サービスが AZ レベルで動作するわけではありません。他の多くはリージョンでの分離を提供します。このようなケースでは、リージョンサービスの可用性がワークロードに必要な全体的な可用性をサポートしていない場合、マルチリージョンのアプローチを検討してみましょう。各リージョンでは、スペアリングと同等のサービスの分離インスタンス化を提供しています

マルチリージョンサービスの構築を容易にするさまざまなサービスがあります。例:

このドキュメントでは、マルチリージョンワークロードを構築する戦略について詳しく説明しませんが、マルチリージョンアーキテクチャの可用性のメリットと、希望する可用性目標を達成するために必要な追加コスト、複雑さ、運用慣行について比較検討する必要があります。

依存関係の MTBF を増やす次の方法は、ワークロードを静的に安定させるように設計することです。例えば、製品情報を提供するワークロードがあるとします。カスタマーが製品をリクエストすると、サービスは外部のメタデータサービスに製品詳細の取得をリクエストします。その後、ワークロードはその情報をすべてユーザーに返します。

ただし、メタデータサービスが利用できない場合、カスタマーからのリクエストは失敗します。代わりに、メタデータをサービスのローカルに非同期でプルまたはプッシュして、リクエストへのレスポンスに使用できます。これにより、重要なパスからメタデータサービスへの同期呼び出しが不要になります。

さらに、メタデータサービスが利用できなくてもサービスは利用できるため、可用性計算の依存関係としてそれを削除できます。この例は、メタデータは頻繁に変更されず、古いメタデータを提供する方がリクエストが失敗するよりも良いという前提に基づいています。別の同様の例として、DNS の serve-stale があります。これは、TTL の有効期限が過ぎてもデータをキャッシュに保持し、更新された回答がすぐに利用できない場合のレスポンスに使用できます。

MTBF を増やす最後の方法は、依存関係の MTBF を増やして障害による影響の範囲を狭めることです。前述のとおり、失敗は二者択一のイベントではありません。障害には程度があります。これがモジュール化の効果です。障害は、そのコンテナによって処理されているリクエストまたはユーザーだけに抑えられます。

その結果、イベント中の障害が減り、影響の範囲が制限されるため、最終的にはワークロード全体の可用性が向上します。

一般的な影響の原因の削減

1985年、Jim Gray は、Tandem Computers での研究中に、障害は主にソフトウェアとオペレーションの 2 つの要因によって引き起こされていることを発見しました。(Jim Gray の「Why Do Computers Stop and What Can Be Done About It? (コンピューターはなぜ停止するのか、そしてそれに対して何ができるのか?)」(1985 年 6 月、Tandem Technical Report 85.7 を参照)。それから 36 年経った今でも、これは真実です。テクノロジーの進歩にもかかわらず、これらの問題に対する簡単な解決策はなく、主な障害の原因は変わっていません。このセクションの冒頭では、ソフトウェアの障害への対処について説明しました。ここではオペレーションと障害の発生頻度の削減に焦点を当てます。

機能と比較した安定性

分散システムの可用性 セクションのソフトウェアとハードウェアの障害発生率のグラフをもう一度見てみると、各ソフトウェアリリースに不具合が追加されていることがわかります。つまり、ワークロードに何らかの変更を加えると、障害のリスクが高まります。これらの変更は通常、当然の結果をもたらす新機能のようなものです。可用性の高いワークロードでは、新機能よりも安定性が優先されます。したがって、可用性を向上させる最も簡単な方法の 1 つは、デプロイの頻度を減らすか、提供する機能を減らすことです。デプロイの頻度が高いワークロードは、そうではないワークロードよりも本質的に可用性が低くなります。ただし、機能を追加できないワークロードはカスタマーの需要に追いついておらず、時間が経つにつれて有用性が低下する可能性があります。

では、どうすればイノベーションを続け、安全に機能をリリースできるのでしょうか。その答えは標準化です。正しいデプロイの方法は何ですか。どのようにデプロイを発注しますか。テストの基準は何ですか。ある段階から別の段階までの待機時間はどれくらいですか。ユニットテストはソフトウェアコードを十分にカバーしていますか。これらの疑問は標準化によって解消されます。また、負荷テストを実施しなかったり、デプロイ段階をスキップしたり、あまりにも多くのホストに早期に展開しすぎることによって引き起こされる問題を防止できます。

標準化を実装する方法は自動化です。これにより、人為的なミスの可能性が減り、コンピューターは得意なこと、つまり毎回同じことを同じ方法で繰り返すことが可能になります。標準化と自動化を両立させるには、目標を設定します。目標は、手動による変更なし、条件付き認証システムのみによるホストアクセス、すべての API の負荷テストの記述などです。運用上の優秀性は文化的規範であり、これには大規模な変更が必要になる場合があります。目標に対するパフォーマンスを確立して追跡することは、ワークロードの可用性に幅広い影響を与える文化的な変化を促進します。AWS Well-Architected 運用上の優秀性の柱は、運用上の優秀性を達成するための包括的なベストプラクティスを提供します。

オペレーターの安全

障害を引き起こす運用上のイベントのその他の主な原因は人です。人間は間違いを犯します。間違った認証情報を使用したり、間違ったコマンドを入力したり、Enter キーを押すのが早すぎたり、重要な手順を見逃したりする可能性があります。手動によるアクションを継続的に実行すると、エラーが発生し、障害につながります。

オペレーターのエラーの主な原因の 1 つは、わかりにくい、直感的でない、または整合性のないユーザーインターフェイスです。Jim Gray は 1985 年の研究で、「オペレーターに情報を求めたり、何らかの機能の実行を求めたりするインターフェースは、シンプルで整合性があり、オペレーターに対する耐障害性がなければならない」とも述べています。(Jim Gray の「Why Do Computers Stop and What Can Be Done About It? (コンピューターはなぜ停止するのか、そしてそれに対して何ができるのか?)」(1985 年 6 月、Tandem Technical Report 85.7 を参照)。この洞察は今でも真実です。わかりづらい、または複雑なユーザーインターフェイス、確認や指示の欠如、あるいは単に不親切な人による言葉が原因で、オペレーターが間違ったことをする原因となった例は、過去 30 年間にわたり業界全体で数多く存在します。

ルール 12

オペレーターが正しいことを簡単に行えるようにします。

過負荷の防止

最後に影響に寄与する一般的な因子は、カスタマー、つまりワークロードの実際のユーザーです。正常なワークロードは使用されるようになりますが、その使用量がワークロードのスケールする能力を上回ることもあります。ディスクがいっぱいになり、スレッドプールが使い果たされ、ネットワーク帯域幅が飽和状態になり、データベース接続の制限に達するなど、さまざまなことが起こり得ます。

これらを解消する確実な方法はありませんが、運用健全性メトリクスを通じて容量と使用率を積極的に監視することで、障害が発生する可能性がある場合、早期に警告を発することができます。負荷分散回路ブレーカーエクスポネンシャルバックオフとジッターによる再試行などの手法は、影響を最小限に抑えて成功率を高めるのに役立ちますが、このような状況では障害はまだ解消されていません。運用健全性メトリクスに基づく自動スケーリングは、過負荷による障害の頻度を減らすのに役立ちますが、使用率の変化に対して十分迅速に対応できない場合があります。

カスタマーが継続的に利用可能な容量を確保する必要がある場合は、可用性とコストのバランスを取る必要があります。容量不足が可用性の低下につながらないようにする 1 つの方法として、各カスタマーにクォータを設定し、割り当てられたクォータの 100% を提供するようにワークロードの容量をスケーリングすることです。カスタマーがクォータを超えるとスロットリングされますが、これは障害ではなく、可用性にも影響しません。また、十分な容量を確保するためには、カスタマーベースを綿密に追跡し、将来の使用率を予測する必要があります。これにより、カスタマーによる過剰消費によって、ワークロードで障害が発生するような状況を回避できます。

例えば、ストレージサービスを提供するワークロードについて検証してみましょう。ワークロード内の各サーバーは 1 秒あたり 100 回のダウンロードをサポートでき、カスタマーには 1 秒あたり 200 回のダウンロードというクォータが提供され、500 人のカスタマーがいます。この数のカスタマーをサポートするには、サービスは 1 秒あたり 100,000 ダウンロードの容量を提供する必要があり、それには 1,000 台のサーバーが必要です。いずれかのカスタマーがクォータを超えると、そのカスタマーはスロットリングされ、他のすべてのカスタマーに十分な容量が確保されます。これは、作業単位を拒否せずに過負荷を回避する 1 つの方法の簡単な例です。