10

私はこのような状況にあります.... 1 つのサーバーと、たとえば数万のクライアントの間でクライアントが開始する SOAP 1.1 通信。クライアントは外部にあり、ファイアウォールを通過し、証明書や https などで認証されます。クライアントはどこにでもあり、通常は独自のファイアウォール、NAT ルーターなどを持っています。リモートの企業オフィスだけでなく、真に外部に存在します。それらは、企業/キャンパス ネットワーク、DSL/ケーブル、さらにはダイヤルアップにある可能性があります。

クライアントは Delphi (2005 年 + 2007 年からの SOAP 修正) を使用し、サーバーは C# ですが、アーキテクチャ/設計の観点からは問題ありません。

現在、クライアントは新しいデータをサーバーにプッシュし、15 分間のポーリング ループでサーバーから新しいデータをプルします。サーバーは現在、データをプッシュしません。クライアントは、プルする新しいデータがあるかどうかを確認するために、「messagecount」メソッドをヒットします。0 の場合、さらに 15 分間スリープし、再度チェックします。

これを 7 秒に短縮しようとしています。

これが 1 つまたは数十のクライアントを持つ内部アプリである場合、サイレントな「リスナー」SOAP サービスを作成し、それにデータをプッシュします。しかし、それらは外部にあり、独自のファイアウォールの背後にあり、時には NAT ルーターの背後にあるプライベート ネットワークであるため、これは実用的ではありません。

そのため、はるかに高速なループでポーリングする必要があります。それぞれが 10 秒ごとにメッセージ数をチェックする 10,000 のクライアントは、帯域幅、サーバー、ファイアウォール、およびオーセンティケーターのリソースを浪費するだけの 1000/秒のメッセージになります。

そのため、自傷行為による DoS 攻撃に相当するものよりも優れたものを設計しようとしています。

サーバーが SOAP メッセージをクライアントに送信 (プッシュ) することは、クライアント側で多くの構成が必要になるため、実用的ではないと思います。しかし、私が知らない代替手段があると思います。そのような:

1) クライアントが Soap 1.1 経由で GetMessageCount() のリクエストを作成し、応答を取得する方法はありますか?新しいデータの場合に追加の応答を取得するために、おそらく 5 ~ 10 分間「待機」します。到着?つまり、サーバーは「0」と言い、1 分後に何らかの SQL トリガー (サーバーは Sql Server 上の C# です) に応答して、このクライアントがまだ「オンライン」であることを認識し、更新されたメッセージ カウント「5」を送信します。 "?

2) 最後の GetMessageCount() リクエストから収集した情報を使用して、クライアントに「ping」するために使用できる他のプロトコルはありますか?

3) 私も知りません。クライアントがGetMessageCount()リクエストを送信できる魔法のプロトコルを探していると思います。これには、「ちなみに、次の1時間で回答が変わる場合に備えて、このアドレスでpingしてください... "。

また、何千もの接続を同時に開いたままにしておく必要があるため、これらの「回線を開いたままにする」スキームのいずれかがサーバーのサイジングに深刻な影響を与えると思います。それはファイアウォールにも影響を与える可能性が高いと思います。

そのようなものはありますか?それとも、私はポーリングにかなりこだわっていますか?

ティア、
クリス

2010 年 4 月 30 日更新:
特にHTTPS/SOAP/ファイアウォールの企業標準から逸脱しない限り、7秒の通知を行うことは簡単でも安価でもないことを実証したので、おそらく2段階のソリューションを売り込むつもりです. フェーズ 1 では、SOAP を介して実行される GetMessageCount を使用して、クライアントに「オンデマンド」でポーリングを行わせます。新しいデータを取得するための「更新」ボタンがあります (これは合理的です。ユーザーは通常、新しいデータの準備ができていると疑う理由があるためです。つまり、オンライン システムでファブリックの色を変更しただけなので、クリックする必要があることを知っているためです)。デスクトップで出荷マニフェストを表示する前に更新すると、説明に色が表示されます.) (これは実際には衣服/ファッションアプリではありませんが、アイデアはわかります.) 2 つの AP を常に同期させるという概念は、ここで説明するテクノロジーを使用して、ホストからプッシュされたリアルタイムの更新を使用して、まだ検討中です。しかし、これを行わなくても機能の 85% を提供できるため、別のリリースに延期されることを期待しています。ただし、概念実証を行い、それが機能することを実証できることを願っています. 戻ってきて、将来のアップデートを投稿します。これについてみんなの助けをありがとう。

4

10 に答える 10

7

HTTP プロトコルを少し「再生」して、クライアント側にある可能性のあるすべてのプロキシ、NAT、およびファイアウォールを通過しながら、必要なものを取得することを検討してください。

あらゆる種類のキャッシュを禁止する方法で、すべてのクライアントにメッセージ カウントの単純な HTTP 要求を実行させます (例: GET http://yourserver.org/getcount/nodeid/timeofday/sequence )。HTTP サーバーのサーバー側の実装では、「カウント」が以前と同じである場合 (つまり、新しいメッセージがない場合)、応答の提供が遅れます。

ブラウザーで実行され、チャット アプリケーションのように動作する Ajax スタイルのアプリケーションに対してこれを行いましたが、ソリューションはさらに高速になる可能性があります。私は TIdHttp サーバーを使用してサーバー側のものを実装しました。これにより、スレッドで単に Sleep() するだけで、クライアントのものへの回答の提供を実際に遅らせることができました。クライアント側からは、応答が遅いサーバーのように見えました。

サーバー側の疑似コード:

function ClientHasMessages(ClientID:Integer; MaxWait:TDateTime):Boolean;
var MaxTime:TDateTime;
begin
  if ClientActuallyHasMessage(ClientID) then Result := True
  else
    begin
      MaxTime := Now + MaxWait;
      while Now < MaxTime do
      begin
        if ClientActuallyHasMessage(ClientID) then
          begin
            Result := True;
            Exit;
          end
        else
          Sleep(1000);
      end;
      Result := False; // TimeOut
    end;
end;

このコードの背後にあるアイデア: 独自のサーバーのスレッドで実行され、おそらく非常に少ないコストでメッセージ数をテストできます。

  • 待機中にネットワーク トラフィックが発生することはありません。
  • スリープ中は CPU を使用しません。
  • これにより、ユーザーはそのメッセージを非常に迅速に知ることができます。
  • これにより、クライアントは待機時間を制御できます(クライアントは、サーバーが応答を受信しなくなるまで応答を遅らせる時間を増やし、その後少し後退します-そうすることで、プロトコルはバグのあるNATに適応しますクライアントが使用するルーター)。
  • 長期間 TCP/IP 通信を行わなくても、すぐに答えを出すことができます。30 秒は簡単に実行できますが、適切な NAT ルーターを使用しているクライアントの場合は、さらに長くなる可能性があります。

これのサイズの縮小はサーバーの要件ですが、実行可能であると言いたくなりました。

  • サーバーの TCP/IP 実装は、かなりの数の同時接続を追跡する必要があります (すべてのクライアントは常にアクティブな HTTP 要求を持っています)。私の Linux NAT マシンは現在 15,000 の接続を追跡しており、基本的にアイドル状態であるため、動作する可能性があります。
  • サーバーは、すべてのクライアント HTTP 要求に対して常にスレッドを開いています。繰り返しますが、これを書くために使用している Server 2008 の「ワークステーション」(このようなとんでもないことを許可してくれた MSDN に感謝します) には、約 1500 のスレッドがあります。アクティブであり、基本的にアイドルでもあります...
  • サーバー側のコードに使用するテクノロジによっては、MEMORY が制限要因になる場合があります。
于 2010-04-21T10:43:09.173 に答える
4

kbmMWを見てみましょう

MS Exchange と同様の方法を使用する可能性があります-tcp/ip を介した接続と認証、次に udp を介したサーバーからクライアントへの更新の通知、次にクライアントが udp 要求を受信し、tcp/ip を介して更新をダウンロードします。

(少なくともそれがMS Exchangeの仕組みを理解している方法です)

于 2010-04-20T15:11:53.937 に答える
3

サーバーへの呼び出しを試みて、更新があるまでサーバーでしばらく (1 分?) 待機することができます。この方法では、サーバーからクライアントへの接続を必要とせず、クライアントにほぼ瞬時に結果を取得できます (1 分以内に更新がある場合は、待機呼び出しを終了します)。これは比較的簡単で、Web アプリで広く (?) 使用されています (Gmail など: このようなバックグラウンド接続があります: 新しいメールが到着すると、すぐに受信トレイに表示されます!)。私はこのようなものを使用します(RemObjects):

function TLoggingViewService.GetMessageOrWait: TLogMessageArray;
begin
  if (Session.Outputbuffer.Count > 0) or
     //or wait till new message (max 3s)
     Session.Outputbuffer.WaitForNewObject(3 * 1000)
  then
    //get all messages from list (without wait)
    Result := PeekMessage;
end;

マイナス点は、接続を比較的長い間開いたままにしておくことです(wifiなどで接続が失われた場合はどうなりますか?)およびサーバーの「負荷」が高い(各接続にはスレッドがあり、開いたままになります:多くのクライアントがある場合は取得できますリソースが不足しています)。

ここでは RemObjects を使用し、TCP + Binmessage を使用します。これは、SOAP + HTTP よりもはるかにオーバーヘッドが低く、非常に高速です! 使いこなせるなら本当にオススメです!(あなたの場合、Delphi には Remobjects が、.Net には RemObjects が必要です)。サードパーティに接続する必要がある場合にのみ SOAP を使用し、インターネット/ファイアウォールのために必要な場合にのみ HTTP を使用してください。SOAP は優れていますが、高いオーバーヘッドとパフォーマンスの問題があります。

これらを組み合わせて使用​​することもできます: バックグラウンド スレッドで単純な (RemObjects) TCP 接続 (低オーバーヘッド) を使用し、10 秒ごとにポーリングし、新しいデータを 5 秒待機します。

于 2010-04-21T06:18:52.177 に答える
3

Delphi での多層開発に関する 2 つの大きな当事者は、components4developers (kbmMW製品については Mark Robinson による回答で説明されています) と RemObjects とその製品RemObjects SDK (彼らには、あなたが望むものに似ているかもしれない良い例があります:プッシュ通知iPhone )。

複雑な環境では、マルチキャスト UDP は役に立たないかもしれませんが、オーバーヘッドの観点からは無敵です。

接続が開いている場合は、双方向に使用できますが (これは .NET リモート処理と WCF でも使用されます)、追加のオーバーヘッドが発生します。

接続を維持する (リソースをロックする) ことと、新しい接続を作成する (時間と待ち時間がかかる) のバランスを見つける必要があります。

--jeroen

于 2010-04-20T19:49:08.170 に答える
3

10,000 クライアントよりもさらに大きなシステムでパフォーマンス テストを行いました。前述の要求/秒の量に達すると、接続/秒、同時オープン接続、ファイアウォールの低速化などの問題に直面する可能性が高くなります。トレント トラッカーが直面する可能性のある問題)。

クライアントが「何か新しいものがあるかどうかを尋ねる」だけでよい場合、実装が簡単な最も軽いプロトコルは UDP であり、次に最も軽いプロトコルは純粋な TCP であり、両方とも Indy クライアントを使用します。

プロトコル自体は、「[yyyy-mm-dd hh:mm:ss] 以降の新しいもの」をサーバーに送信し、1 バイトの数字 (256 の回答が可能) で応答するという単純なものである可能性があります。

TCPを使用すると、「パイプ」を数分間開いたままにしておくという追加の利点があり、x秒ごとに「何か新しい」メッセージを送信できます。また、クライアントが定期的にパイプ内のデータをチェックしている場合、TCP を使用すると、何かが発生したときにサーバーがパイプ (クライアント) に情報を「プッシュ」することができます。

于 2010-04-24T18:03:04.823 に答える
2

複数のサーバー間で可能な限り負荷を分散しようとします。そのために、私は次のことをします:

  1. クライアントは、通知を受け取るためにサービスに登録します。一定時間 (15 分間) 有効なセッション ID を取得します。
  2. サーバーは、どの登録済みクライアントに受信メッセージがあるかを定期的にチェックし、そのようなクライアントのリストを生成します (技術的には、DMZ 内の別の DB にプッシュします)。
  3. 非常に単純なプロトコルに従う多数の「プッシュ通知」サーバーを実行します。それらはセッション ID を含む URL クエリを取得し、短い HTTP 応答で応答します。メッセージを取得するためにアドレス指定する SOAP サーバー。追加のパフォーマンスについては、HTTP 1.1 と永続的な接続を使用できます。
  4. クライアントは、必要に応じてこれらのプッシュ通知サーバーをプールします。それらは非常にシンプルで厳密に読み取り専用であるため、クエリに非常に高速に応答でき、スケールアウトも容易です。
  5. クライアントが 302 応答を受信すると、正しい SOAP サーバーに接続し (必要に応じて負荷分散に使用することもできます)、メッセージをプルできます。

ここではセキュリティに注意する必要があります。まず、プッシュ通知サーバーに HTTPS を使用しないことをお勧めします。代わりに、クライアントが通知を要求したときに交換されたセッション キーを使用して、応答の内容に署名できます。その後、クライアントは回答を検証する責任があります。ステータスだけでなく、SOAP サービス URL にも署名する必要があることを忘れないでください。

少し複雑ですが、ステータスと実際のメッセージ トラフィックを切り離すことで、ソリューションをより簡単にスケールアウトできます。また、実際にデータを交換するまで、高価な SSL ネゴシエーションを行う必要はありません。

于 2010-04-29T13:34:51.313 に答える
2

これには RemObjects SDK の「イベント」を使用しますが、これは適切ではない可能性があります。

a: SOAP ではなく、RemObjects 独自のバイナリ プロトコルでのみ動作します (つまり、クライアントは RO コードを組み込む必要があります)。

b: 基本的には、「ラインをオープンにしておく」アプローチです。そのため、10,000 クライアントへのスケーラビリティが問題になる可能性があります。

10K ソケットを開いたままにしておくと実際にどのようなオーバーヘッドがあるかを確認するためだけに、いくつかのテストを試してみます。数ギガの追加のサーバー メモリが必要なだけであれば、安価な修正になるでしょう。また、ソケットはクライアント エンドから開かれるため、ファイアウォールの問題が発生することはありません。ファイアウォールができる最悪のことは、ソケットを閉じることです。そのため、クライアントはソケットを再度開く必要があります。

于 2010-04-29T13:43:37.687 に答える
1

1台のサーバーと10,000以上のクライアントがあり、数秒ごとに更新を行う必要がある場合はいつでも、問題が発生します。さらにいくつかのサーバーを取得し、クライアントのバックグラウンドスレッドでクライアントを接続したままにします。このスレッドは、最初に接続し、組み込みのキープアライブメカニズムを使用してサーバーから通知が届くのを待ちます。

サーバーから現在接続されていないクライアントにプッシュしようとしている場合、クライアント環境を制御できない場合は幸運を祈ります。クライアントが開始する接続を強制されているように聞こえます。

于 2010-04-21T03:38:02.323 に答える
1

iPhone のプッシュ通知は、リモート デバイスが iPhone の場合にのみ機能します。他の唯一のオプションは、接続を開いたままにする (ただしほとんどアイドル状態) か、クライアントからポーリングすることです。

呼び出しを単純化することで、ポーリングのオーバーヘッドを削減できる場合があります。単純な Web アクションを使用して最大のメッセージ番号をクライアントに返し、クライアントに単純な HTTP GET を実行させてこの番号を受信させます。これにより、帯域幅の量が削減され、シンプルに保たれます。その後、クライアントが更新されたデータを取得する必要がある場合は、完全な SOAP 呼び出しを行うことができます。

于 2010-04-20T23:44:58.943 に答える
0

左翼手で何かが少しアウト。

更新の準備ができていることを示すフラグを取得するためだけに認証が必要なのはなぜですか? 認証ファイアウォールの外側に、またはクラウド内にさえもマシンを用意しないでください。これらの「利用可能なものは何でも」要求を処理するだけです。次に、何かが利用可能な場合は、クライアントにフープを通過させて実際のデータを取得します。この要求サーバーは、実サーバーから 7 秒間の getcount を実行できます。

現在、単純な「フラグ」の場合、データはほとんどなく、セットアップ時間もほとんどありません。

それでも数千のリクエストがありますが、完全に認証されたリクエストと比較してオーバーヘッドが最小限の数千のリクエストです。

于 2010-11-11T04:58:44.060 に答える