グレースフル・デグラデーション(Graceful Degradation)は、直訳すると「優美な劣化」となりそうですが、つまりサービスが満足に動かないときに影響を限定的にするにはどうすればいいかというアイデアです。これについて論じた記事「How To Design Software For Graceful Degradation」の抄訳です。

SREing、つまり人としての「エンジニア」ではなくプラクティスとしての「エンジニアリング」について考えたとき、インフラのキャパシティを制御するだけではサイトの信頼性を保てない場面はあります。グレースフルな挙動を実現するためには、アプリケーションや、サービスのビジネス的特性も考慮すべき要素になってくるでしょう。


インフラストラクチャ層からアプリケーションのフロントエンドまで、システムには限界というものがあります。しきい値を超えてしまうと、システムは予想外の動作をしてしまいます。サービスの劣化です。サービス停止が起こります。そして、障害対応として問題の根本原因を発見して修正すればいいと考えがちですが、多くの場合、単一の原因があるわけではありません。需要の急激なスパイクが起こると、サービスは多くのリクエストをメッセージキューに送ることになります。これは通常の動作であり、特に問題はありません。しかし、メッセージキュークラスタに設定ミスがあり、スケールアップがうまく動作しなかったらどうでしょうか。劣化し、めちゃくちゃな状態になったサービスを目の当たりにすることになります。

特定の挙動を予測することは難しいかもしれませんが、SREやDevOpsチームは、サチュレーションやレイテンシの劣化、過剰なワークロードなど、マクロレベルな問題に備えたプランを立てることができます。そのような計画づくりの一環として、機能を制限することによって壊滅的な障害を防ぐ手法があり、グレースフル・デグラデーション(Graceful Degradation: 上品な劣化)と呼ばれています。たとえば、ネットワークエンジニアがネットワークルーティングの設計をする際に、ネットワークのパスが利用できないときはトラフィックを再ルーティングすることがあります。これにより、サチュレーションとレイテンシは増加するかもしれませんが、トラフィックは最終的に宛先に到達することになります。同様に、大規模エンタープライズアプリケーションでも劣化を緩やかにするよう設計することは大きなメリットがあります。

システム設計にレジリエンス(回復力)とグレースフル・デグラデーションを備えるためには、4つの既成のプラクティスがシステムに適用できないか、検討してみましょう。ユーザの影響が大きいものから始めるのがおすすめです。

  1. ワークロードを削除する
  2. ワークロードを遅延させる
  3. サービス品質を低下させる
  4. キャパシティを追加する

一つ一つ、詳しく見ていきましょう。

1. ワークロードを削除する

発電施設の需要がキャパシティを超えると、システム全体にダメージを与える危険性がでてきます。その場合、エンジニアはグリッドの一部の電力を停止することで、大規模な障害を防ぎます。これはロードシェディングとして知られているもので、分散システムへの過剰な負荷に適した対応パターンです。例えば、API コールやデータベース接続、永続的なストレージへのリクエストがキャパシティを超えると、リクエストの一部を停止させることがあります。

ロードシェディングを行う際、どのリクエストを削除するかを決定することが設計上重要になります。シンプルなアプローチは、しきい値を超えたときにすべてのリクエストを削除する方式です。実装は比較的簡単ですが、サービスレベルの違いや特定のリクエストを優先させることはできません。例えば、ヘルスチェックは他のリクエストよりも優先されるべきでしょう。

2. ワークロードを遅延させる

サービスによっては、ロードシェディングができない場合があります。マーケティングキャンペーンが大成功して、新しい顧客がECサイトに殺到しました。このときは、注文取引のリクエストを落としたくないはずです。より良い選択肢は、過剰な作業負荷の処理を遅延処理させることでしょう。このテクニックでは、リクエストの生成と、それに対する処理を切り離します。

Apache KafkaGoogle Cloud Pub/Sub などのメッセージキューは、この種の非同期処理のためにデータをバッファリングするために広く使われています。しかし、この手法を使用する際には、トランザクションの範囲に注意が必要です。それぞれのサービス内部ではトランザクションを実装することができますが、一連のサービス呼び出し全体を成功または失敗にしなければならないときに、複数のサービスにまたがるトランザクションが正しくロールバックされるようにするには、追加のロジックが必要になるかもしれません。

3. サービスの品質を低下させる

ワークロードがあふれているが、削除したり遅延させたりしたくない場合には、サービスの品質を下げることも選択肢に入ります。例えば、システムにストレスが掛かった場合、利用可能な機能を一時的に減らしたり、リクエストを処理するためのデータベースクエリを、決定論的なクエリのかわりに近似的な値を出すクエリに切り替えたりすることも考えられます。このアプローチの利点は、一部のリクエストを削除することなく、すべてのリクエストにサービスを提供できることです。また、タイムシフトに伴う処理の遅延を回避したいときにも有効です。

4. キャパシティを追加する

理想的には、顧客体験の観点からは、ワークロードを削除したり遅延させたり、サービス品質を低下させたりしないのがベストです。ワークロードのスパイク対応として、キャパシティを追加することのがほとんどの場合で最善な選択肢でしょう。パブリッククラウドでは、VM等多くのインフラストラクチャ資源がオートスケールに対応いて、利用可能なリソースが上限に達したり枯渇したりしない限り、人に介入がほとんど必要ありません。例えば、パブリッククラウドのゾーン障害が発生した場合、リージョン内の残りのゾーンのリソースの需要が急増して、枯渇するかもしれません。

最終的には、ある程度の高度なキャパシティ・プランニングプロアクティブなモニタリングによって、チームはより回復力のあるサービスを構築することができるようになるでしょう。

転ばぬ先のSRE

モダンなソフトウェアの究極の姿は100%のアップタイムですが、SREやDevOpsチームは、ワークロードのパターンや複雑な障害モードに備える必要があります。避けられないことですが、ある程度、予期することは可能です。アプリケーションを設計する際にこれらの要因を考慮に入れておくことで、回復力(レジリエンス)があり、劣化(デグラデーション)に強いシステムを構築する準備が整うでしょう。

願わくば、稼働時間に影響を与えずに済みますように…。

グレースフル・デグラデーションだけではなく、クラウド体験を完全に監視する方法については、電子ブック「Adopt, Experiment, and Scale: Core Capabilities for Cloud Native Success」をあわせてご覧ください!