2つのサーバーに照会し、最速の応答のみを消費することは、どのような条件で(もしあれば)良い習慣ですか?


12

なぜjavascriptを使用するのかについて、コミュニティで削除された質問をSOに尋ねましたPromise.race

何らかの値を計算する2つのサービスがある場合、それらを並行してクエリし、1つをクエリし、失敗を待ってから2番目をクエリするのではなく、最初に返される値を使用できます。

私は冗長性とこのユースケース全般についてグーグルで調べましたが、何も見つかりませんでしたし、POVから、応答を使用しない場合はサーバー/サービスにワークロードを追加することは決して良い考えではありません。


おもちゃの例:クイックソートを常に使用するのではなく、データをコピーして、クイックソート、マージソート、ヒープソートなどに送信します。入力が異常なケースであるかどうかを確認する必要はありません。以下のためのあらゆる人の、それがためにpathalogicalケースではありませんので、すべてのそれらの
Caleth

Dean and Barrosoの論文The Tail at Scaleは、このアプローチのバリエーションを「ヘッジされたリクエスト」と呼んでいます。また、エラー率と遅延のロングテールの変動性を制御するためのいくつかの関連するアプローチの長所と短所についても説明します。
ダニエル・プライデン

2番目の「サーバー要求」は偽物である可能性があります。5秒間だけ待ってから、プレースホルダー応答を返すことができます。これにより、実際のリクエストでタイムアウトが発生します。
user253751

Lyftを注文してから、Uberを注文してください。最初に来た方を選んでください。
user2023861

@ user2023861このアナロジーでは、1人のドライバーがあなたの場所に向かって無意味に運転している間、彼/彼女は代わりに別のリクエストに応じることができました
アデリン

回答:


11

これはもっと経済的な問題だと主張します。しかし、それはエンジニアができるべき判断判断です。したがって、私は答えています。

私は答えを4つの部分に分けています。

  • 危機管理
  • 戦略
  • 費用
  • 直感

危機管理

そのため、クライアントがサーバーからの応答を取得できない場合があります。これはプログラム上のエラーによるものではないと想定します(そうでない場合、解決策は修正することですので、それを行ってください)。代わりに、それはあなたの制御を超えた偶然の状況のた​​めでなければなりません...

しかし、あなたの知識を超えていません。あなたが知っている必要があります:

  • どのくらいの頻度で発生しますか。
  • どのような影響がありますか。

たとえば、失敗して再試行が発生するのは約2%の時間だけである場合、おそらく対処する価値はありません。それが時間の約80%で起こるならば、まあ...依存します...

クライアントはどれくらいの時間待つ必要がありますか?そして、それはどのようにコストに変換されますか...あなたが見るように、あなたは通常のアプリケーションにわずかな遅延があります、それはおそらく大したことではないでしょう。それが重要であり、リアルタイムアプリケーションまたはオンラインビデオゲームがある場合、これはユーザーを追い払うでしょう。おそらく、より多くのまたはより良いサーバーに投資するほうがよいでしょう。そうでない場合は、おそらく「ロード中」または「サーバーを待機中」というメッセージを表示できます。遅延が非常に大きい(数十秒程度)場合を除き、通常のアプリケーションでも遅延が大きすぎる可能性があります。


戦略

上で言ったように、この問題を解決する方法は複数あります。既にtry-fail-retryループを実装していると仮定します。それでは、見てみましょう...

  • 読み込みメッセージを入れてください。安価で、ユーザーの保持に役立ちます。
  • 並列クエリ。速くなることも、失敗することもあります。冗長サーバー(高価になる可能性があります)が必要になり、サーバー時間とネットワークトラフィックが無駄になります。
  • 並行してクエリを実行して、より高速なサーバーを確立し、それ以降を使用します。速くなることも、失敗することもあります。冗長サーバーが必要になり(高価になる可能性があります)、サーバー時間とネットワークトラフィックを無駄にしません。

さて、これらはまだ失敗する可能性があると言っています。サーバーへのクエリが失敗する可能性が80%あると仮定すると、2つのサーバーへの並列クエリが失敗する可能性は64%になります。したがって、まだ再試行する必要があります。

より高速なサーバーを選択して使用し続けることのボーナスの利点は、ネットワークの問題により高速なサーバーが故障する可能性が低いことです。

リクエストが失敗する理由を理解できれば、それを思い出してください。障害を防ぐことができなくても、状況をよりよく管理するのに役立ちます。たとえば、サーバー側でより多くの転送速度が必要ですか?

もう少し:

  • 世界中に複数のサーバーを展開し、ジオロケーションごとにサーバーを選択します。
  • サーバー側で負荷分散を行います(専用のマシンがすべてのリクエストを受け取り、それらをサーバーに送ります。そこで並列処理を行うか、より良いバランス戦略をとることができます)。

そして誰があなたがこれらのうちの1つだけをしなければならないと言ったのですか?読み込みメッセージを入れ、wrold全体に分散している複数のサーバーにクエリを実行して、より高速なものを選択し、それ以降のみを使用して、失敗した場合はループで再試行し、それらのサーバーのそれぞれを負荷分散を備えたマシンのクラスターにすることができます。何故なの?まあ、コスト...


費用

4つのコストがあります。

  • 開発コスト(通常は非常に安い)
  • 展開のコスト(通常は高い)
  • コストランタイム(アプリケーションの種類とビジネスモデルに依存)
  • 失敗のコスト(おそらく低いが、必ずしもそうではない)

それらのバランスを取る必要があります。

たとえば、満足したユーザーごとに約1ドル稼げるとしましょう。1日に3000人のユーザーがいること。リクエストが約50%失敗すること。そして、ユーザーの2%は、リクエストが失敗したときに支払いをせずに去ります。これは、1日あたり30ドル(3000 * 50%* 2%)失うことを意味します。さて、新しい機能の開発には100ドルかかり、サーバーの展開には800ドルかかります-そして、ランタイムコストを無視すると-((100 + 800)/ 30 )30日。これで、予算を確認して決定できます。

これらの値は現実を代表するものとは考えないでください。私は数学の便宜のためにそれらを選びました。

補遺:

  • 私も詳細を無視していることを忘れないでください。たとえば、デプロイコストはほとんどありませんが、CPU時間を支払う必要があるため、それを考慮する必要があります。
  • 一部のクライアントは、冗長なリクエストでデータパッケージを無駄にしないと感謝する場合があります。
  • 製品の改善は、自然な広告をもたらすのに役立つ場合があります。
  • 機会費用を忘れないでください。他の何かを開発すべきですか?

問題は、バランスコストの観点から問題を検討する場合、検討する戦略のコストを推定し、この分析を使用して決定できることです。


直感

経験によって育てば直観。この種の分析を毎回行うことを提案しているわけではありません。一部の人々は、それは大丈夫です。これについてある程度理解し、直観を深めることをお勧めします。

さらに、工学では、実際の科学から得た知識の他に、実践で学び、何が機能して何が機能しないかのガイドラインをまとめます。したがって、最新技術が何であるかを見るのが賢明です...しかし、時々、あなたはあなたの地域の外を見る必要があります。

この場合、私はオンラインビデオゲームを見ます。ロード画面があり、複数のサーバーがあり、待ち時間に基づいてサーバーを選択します。また、ユーザーがサーバーを切り替えることもできます。私たちはそれが機能することを知っています。

リクエストごとにネットワークトラフィックとサーバー時間を無駄にする代わりに、それを行うことをお勧めします。また、サーバーが冗長であっても障害が発生する可能性があることに注意してください。


2
私はそれを言う必要はないと思いますが、これは素晴らしい答えです:)最初の10行でそれを受け入れることは知っていましたが、失敗して最後まで読む機会を与えました。あなたはしませんでした
アデリン

9

クライアントの時間がサーバーの時間よりも重要な場合、これは受け入れられます。

クライアントが高速かつ正確である必要がある場合。複数のサーバーへのクエリを正当化できます。また、有効な回答が受信された場合は、リクエストをキャンセルすると便利です。

そしてもちろん、サーバーの所有者/管理者に相談することは常に賢明です。


リクエストをキャンセルする必要があるのはなぜですか?確かにそれは主観的です。
JᴀʏMᴇᴇ

@JᴀʏMᴇᴇ、それは妄想で構築されています。私はかつて、キューをクリアしないシステムで作業し、キューがいっぱいになるとクラッシュしました(はい、それはプロのソフトウェアでした)。
トゥーンクリティ

4

この手法により、待ち時間を短縮できます。サーバーの応答時間は決定的ではありません。大規模では、少なくとも1つのサーバーが応答時間の低下を示している可能性があります。したがって、そのサーバーを使用するものはすべて、応答時間が遅くなります。複数のサーバーに送信することにより、パフォーマンスの低いサーバーと通信するリスクを軽減します。

コストには、追加のネットワークトラフィック、無駄なサーバー処理、およびアプリケーションの複雑さが含まれます(これはライブラリに隠れていると考えられます)。これらのコストは、未使用のリクエストをキャンセルするか、2番目のリクエストを送信する前に少し待つことで削減できます。

ここに1枚の紙、もう1枚あります。Googleの論文の実装も読んだことを覚えています。


2

私は他の答えにほぼ同意しますが、これは実際には非常にまれであると思います。を使用する場合のより一般的で合理的な例を共有したかったのですがPromise.race()、たまたま数週間前にそれを使用しました(まあ、Pythonの同等物)。

並行して実行できるタスクと、他のタスクより先に実行する必要があるタスクの長いリストがあるとします。依存関係なしですべてのタスクを開始し、でそのリストで待機できPromise.race()ます。最初のタスクが完了するとすぐに、その最初のタスクに依存していたタスクを開始できPromise.race()、元のリストの未完了のタスクと組み合わせた新しいリストで再び開始できます。すべてのタスクが完了するまで繰り返し続けます。

注JavascriptのAPIは、このために理想的に設計されていません。動作するのはほとんど最低限であり、かなり多くのグルーコードを追加する必要があります。ただし、私のようなポイントはrace()、冗長性のためにめったに使用されないような機能です。これらは主に、すべてのプロミスの結果を実際に必要とする場合に使用されますが、すべてのプロミスの完了を待ってから次のアクションを実行したくない場合に使用します。


問題は、少なくともJavascriptのPromise.raceでは、実際にraceメソッドを実行するたびにタスクを開始することです。未完成のタスクではなく、以前に実行されたものに関係なく、新しいタスクのセットになります(そのロジックをタスクレベルで実装しない限り)。そうでなければ元のリストは忘れられ、最初のタスクの戻り値のみが残ります
アデリン

1
Javascriptのプロミスnew Promiseは、呼び出されたときに熱心に開始され、Promise.race()呼び出されたときに再起動されません。いくつかのプロミスの実装は怠butですが、熱心な方がはるかに一般的です。コンソールにログを記録するプロミスをコンソールに作成してテストできます。すぐにログが表示されます。次に、その約束をに渡しPromise.race()ます。再びログに記録されないことがわかります。
カールビーレフェルト

ああ、そうです。しかし、promise.race
Adelin

だからこそ、APIは理想的な設計ではないと言ったのです。元のタスクセットをどこかの変数に格納する必要があります。
カールビーレフェルト

1

技術的な考慮事項に加えて、実際のビジネスモデルの一部である場合、このアプローチを使用できます。

このアプローチのバリエーションは、広告のリアルタイム入札では比較的一般的です。このモデルでは、パブリッシャー(広告スペースプロバイダー)は、広告主(広告プロバイダー)に特定のユーザーのインプレッションに入札するように依頼します。だから、すべてのそのような印象のために、あなたは、各広告主が提供するエンドポイント(あるいは、ご自身のサーバー上のエンドポイントとして動作している広告主が提供するスクリプト)への印象の詳細をクエリを送信し、加入広告主のそれぞれを照会しますレースこれらのリクエストはすべてタイムアウト(100ミリ秒など)になり、他のリクエストを無視して最高入札額を取得します。

クライアントの待機時間を短縮するのに役立つこの特定のバリエーションは、その値を超える最初の広告主の入札がすぐに受け入れられるように(または入札のいずれも超えない場合、パブリッシャーに入札の最小目標値を許可することです値、最大値が取得されます)。したがって、このバリエーションでは、最初に到着したクエリが勝ち、他のクエリが同じかそれ以上であっても破棄されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.