banner
田野放空

田野放空

认真扮演一个擅长白日做梦的普通人

如何デザインする精壮なサービス

最近辞職した後、面接と履歴書の準備中に、以前の仕事中に発生したサービスの問題を振り返りました。いくつかの事故では、ピーク時のトラフィックによっていくつかのサービスがダウンした可能性があります。これはデータベースの問題やメモリなど、さまざまな問題によるものです。その深層には、サービス自体が十分に堅牢でないことがあります。サービスのいくつかのノードがダウンした後、リトライストームが発生し、それによって雪崩が発生します。これらのサービスがメインプロセスのサービスである場合、システム全体が雪崩を引き起こす可能性があります。

image-20230401221427201

多くのサービスは、上記の図に示すように、負荷が最大限に達する前に正常にサービスを提供できますが、トラフィックがサービスが耐えられる最大限を超えると、外部のサービス能力は急激に低下し、トラフィックが過負荷でなくても、トラフィックを完全にゼロにしても、サービス能力はなかなか回復しません。

場合によっては、サービス能力が回復するのを待つのが非常に困難であり、上位のトラフィックが戻ってきた後、サービスは瞬時に多くの人工または自動のリトライリクエストによってダウンします。

もし私たちのバックエンドサービスがこのように「もろい」場合、過負荷が発生するとすぐにダウンしてしまい、なかなか立ち上がることができない場合、私たちの安定性保証の仕事はできません。大規模なアプリケーションでは、数千のサービスがあり、それぞれのサービスには多くのノードがあります。このような場合、すべてのノードの安定性を保証し、システムがトラフィックによってダウンしないようにすることは非常に困難です。これは実現不可能な状況です。予期しない局所的な異常は常に発生するからです。

したがって、私たちはアプリケーション全体を堅牢にする必要があります。各サービスは一定の堅牢性を持つ必要があります。個々のサービス自体(単一のマシンまたは分散システムであるかどうかに関係なく)に対して、この要件は非常に高くなく、実現するのはそれほど難しくありません。

image-20230401222233706

私たちは、「堅牢な」サービスを提供するために、負荷下でのパフォーマンスが上記の図に示すようになるようにする必要があります。負荷が増加すると、出力は線形に向上し、外部の負荷がサービスの理論的な最大負荷を超えた後、一時的な揺れを経て、外部の負荷がどれほど高くても、サービスは安定して外部に出力され、この出力は理論的な最大負荷に近いことが望ましいです。つまり、「堅牢な」サービスは、過負荷の状況でも安定した出力サービスを提供できるべきであり、処理能力を超えるリクエストは断固として拒否するべきです。

  • 各サービスの各ノードには、自身のサービス負荷をリアルタイムに表す指標が必要です。指標がサービス能力の上限を超える場合、サービス能力を超えるリクエストを拒否する必要があります。
  • サーバー側とクライアント側(ここでのクライアントは単にアプリではなく、このサービス自体のクライアントであり、通常はバックエンドの負荷状況を知るために統合されるものです。別のサービス内の SDK である場合もありますし、アプリ内の SDK である場合もあります)の間にはフィードバックメカニズムが必要であり、クライアントはバックエンドの負荷状況を把握し、自身の戦略を調整できる必要があります。

一般的に言って、各サービスの各ノードには次のようなことが必要です:1. 自分が忙しいかどうか、限界に近づいているかを把握する必要があります。2. 忙しい場合はクライアントに通知する必要があります。クライアントがそれを知らないと、うっかりしてサービスをダウンさせてしまいます...

次に、これらの 2 つのポイントについて、どのようにして自分のサービス負荷を表す指標を見つけ、過負荷時にクライアントと協議するかについて詳しく説明します。

サービス負荷を表す指標#

サービス負荷を表す指標とは、この指標がある閾値を超えると、サービスノードのサービス能力が急激に悪化し、長時間回復しないことを意味します。

私たちは、負荷テストを使用して、標準的なサーバー環境での適切な QPS、TPS などの値を見つけることができます。そして、制限流量、断線などのツールを使用してピーク値を制限することができます。ただし、実際の状況に応じて、制限のピーク値を一定の範囲内に設定することができます。

  1. サービスノードが水平にスケーリング可能な場合、非常に正確である必要はありません。サービスの負荷を CPU や他のリソースの限界まで追い込む必要はありません。負荷テストの結果に基づいて、あまり攻撃的ではない値を設定することができます。混合デプロイやオーバーセールを使用して、サーバーリソースの利用率をさらに高めることができます。
  2. タイムアウト時間を考慮する必要があります。処理が完了しても、クライアントがタイムアウトしている可能性があるため、リクエストの返信は破棄されるだけです。
  3. いくつかのマシンが他の機能のサービスを実行する可能性があることを考慮する必要があります。たとえば、マシンのモニタリングツール、プライマリとセカンダリのノード同期機能、ハートビート機能などです。したがって、閾値の設定では余裕を持たせる必要があります。より詳細なサービスでは、リクエストを優先度ごとに分類し、異なるカウンターを設定することも考えられます。
  4. このカウンターの閾値を自動的に調整する自己適応型のものにすることはできるのかと思うかもしれませんが、実際にはほとんどの場合、それは必要ありません。シンプルなほどエラーが少なくなります。ほとんどの場合、単一のノードのパフォーマンスにこだわる必要はありません。現在のマシンの爆発的な時代において、サービスの安定性はマシンよりも高価です。

クライアントとサーバーの協調#

正直なところ、私はクライアントについてはあまり詳しくありませんが、この問題は実際にはバックエンドがビジー状態でのリトライロジックの最適化です。

クライアントのリトライ戦略は、非常に精巧なロジックであるべきですが、非常に見落とされやすいものです。一般的なリトライ戦略では、シンプルな一定間隔のリトライや、等比数列やフィボナッチ数列などのリトライ間隔を徐々に長くすることを考える人が多いです。

しかし、リトライは実際には 2 つの問題を解決するためのものです。1 つはネットワークのパケットロスや瞬断に対するフェイルオーバーであり、もう 1 つはサーバーノードの障害に対するフェイルオーバーです。前者に対しては、リトライ間隔はできるだけ短いほうが良いですが、後者に対しては、この間隔が短すぎるとリトライストームを引き起こし、バックエンドノードをさらに悪化させる可能性があります。しかし、悲劇は、クライアントの視点から見ると、実際にどのような状況が発生しているのかを区別することができないということです。

したがって、最も簡単な解決策は、サーバーノードがビジー状態の場合、受信したリクエストを単純に破棄するのではなく、これらのリクエストに対してすべて RET_BUSY をクライアントに返すことです。クライアントが RET_BUSY を受け取ると、現在のリトライロジックから抜け出し、リトライの間隔を長くするようにすべきです。さらに、サーバーは自身の状況に応じて返り値をグレード分けすることができます。たとえば、RET_RETRY をクライアントに返し、クライアントにすぐにリトライを開始させ、RET_BUSY および RET_VERY_BUSY をクライアントに異なるリトライサイクルに引き伸ばすことができます。ここでは、非常に多くの精巧なプレイがあり、さまざまな複雑な問題を解決できます。皆さんは自分のエンジニアリングシナリオに合わせて実践してみてください。

ここまで、私たちは「堅牢な」サービスの作り方について説明しました。本質的には、非常にシンプルなエンジニアリング手法を使用して、自己のビジー度合いを初歩的に認識できるサーバーサイドと、サーバーのビジー度合いに応じて自動的にリトライできるクライアントを実装することで、外部のリクエストの圧力がどれほど大きくても、制御可能な出力を提供できるようにすることです。

実際のエンジニアリング実践では、サーバーノードは、平均 CPU 利用率が 70%を超え、瞬時の CPU 利用率が 90%を超える状況で、持続的な安定した外部サービスを提供できるようにする必要があります。テスト環境では、限界状況での持続的な安定した出力を実現できるようにする必要があります。

上記の堅牢性を実現するために改造が必要なサービス#

上記のメカニズムは RPC フレームワークに組み込むことができ、要件がそれほど高くないほとんどのサービスには十分です。

分散ストレージシステムは、パフォーマンスの問題に対してより高い要求を持っています。ストレージシステムの安定性におけるエンジニアリングの難しさは、最も複雑で基本的なものです。ストレージノードは単純な再起動では問題を解決できません。また、リソースの消費次元が複雑で、CPU 以外にもメモリやページキャッシュ、ネットワークスループットと割り込み、ディスクの IOPS とスループットなど、多くのリソースの考慮が必要です。さらに、流量制限後、通常、ストレージシステムは迅速にサービスを回復することはできません(例えば、マスタースレーブ同期を待つ必要がある、マイナーやメジャーコンパクションを待つ必要がある、ディスクフラッシュを待つ必要があるなど)。したがって、オンラインストレージシステムの堅牢性には、通常、より多くの要素を考慮する必要があります。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。