12

C# で記述された ASP.NET 3.5 サーバー アプリケーションがあります。HttpWebRequest と HttpWebResponse を使用して、REST API への送信要求を行います。

これらのリクエストを別々のスレッドで送信するテスト アプリケーションをセットアップしました (サーバーに対する並行性をぼんやりと模倣するため)。

これは、コードに関する質問というよりも、Mono/Environment に関する質問であることに注意してください。したがって、以下のコードは逐語的ではないことに注意してください。機能ビットのカット/ペーストだけです。

ここにいくつかの疑似コードがあります:

// threaded client piece
int numThreads = 1;
ManualResetEvent doneEvent;

using (doneEvent = new ManualResetEvent(false))
        {

            for (int i = 0; i < numThreads; i++)
            {

                ThreadPool.QueueUserWorkItem(new WaitCallback(Test), random_url_to_same_host);

            }
            doneEvent.WaitOne();
        }

void Test(object some_url)
{
    // setup service point here just to show what config settings Im using
    ServicePoint lgsp = ServicePointManager.FindServicePoint(new Uri(some_url.ToString()));

        // set these to optimal for MONO and .NET
        lgsp.Expect100Continue = false;
        lgsp.ConnectionLimit = 100;
        lgsp.UseNagleAlgorithm = true;
        lgsp.MaxIdleTime = 100000;        

    _request = (HttpWebRequest)WebRequest.Create(some_url);


    using (HttpWebResponse _response = (HttpWebResponse)_request.GetResponse())
    {
      // do stuff
    } // releases the response object

    // close out threading stuff

    if (Interlocked.Decrement(ref numThreads) == 0)
    {
        doneEvent.Set();
    }
}

Visual Studio Web サーバーのローカル開発マシン (Windows 7) でアプリケーションを実行すると、numThreads を上げて、1 人の「ユーザー」でも 100 人でも、最小限の変動で同じ平均応答時間を得ることができます。

Mono 2.10.2 環境でアプリケーションを Apache2 に公開およびデプロイすると、応答時間はほぼ直線的に変化します。(つまり、1 スレッド = 300 ミリ秒、5 スレッド = 1500 ミリ秒、10 スレッド = 3000 ミリ秒)。これは、サーバー エンドポイント (異なるホスト名、異なるネットワークなど) に関係なく発生します。

IPTRAF (およびその他のネットワーク ツール) を使用すると、アプリケーションがすべての接続をルーティングするために 1 つまたは 2 つのポートのみを開き、残りの応答を待機する必要があるように見えます。

同様の PHP アプリケーションを構築し、同じリクエストを使用して Mono にデプロイしました。レスポンスは適切にスケーリングされます。

Mono と Apache で考えられるすべての構成設定を実行しましたが、2 つの環境間で (少なくともコードで) 唯一異なる設定は、Mono では ServicePoint SupportsPipelining=false であり、私の環境では true である場合があることです。機械。

何らかの理由で ConnectionLimit (デフォルトの 2) が Mono で変更されていないようですが、指定されたホストのコードと web.config の両方でより高い値に設定しています。

私と私のチームが重要なことを見落としているか、これが Mono の何らかのバグであるかのどちらかです。

4

3 に答える 3

9

でボトルネックにぶつかっていると思いますHttpWebRequest。Web 要求はそれぞれ、.NET フレームワーク内の共通のサービス ポイント インフラストラクチャを使用します。これは、同じホストへのリクエストを再利用できるようにすることを意図しているように見えますが、私の経験では 2 つのボトルネックが発生します。

まず、サービス ポイントは、HTTP 仕様に準拠するために、既定で特定のホストへの同時接続を 2 つだけ許可します。ServicePointManager.DefaultConnectionLimitこれは、静的プロパティをより高い値に設定することでオーバーライドできます。詳細については、このMSDNページを参照してください。個々のサービス ポイント自体については既に対処しているように見えますが、サービス ポイント レベルでの同時ロック スキームにより、これを行うとボトルネックが発生する可能性があります。

ServicePoint次に、クラス自体のロックの粒度に問題があるようです。キーワードのソースを逆コンパイルして調べるとlock、インスタンス自体を使用して同期し、多くの場所で同期を行っていることがわかります。HttpWebRequests特定のホストの Web リクエスト間でサービス ポイント インスタンスが共有されているため、私の経験では、より多くのホストが開かれるとボトルネックになりがちで、スケーリングが不十分になります。この 2 番目のポイントは、主に個人的な観察と情報源の調査です。私はそれを信頼できる情報源とは見なしません。

残念ながら、私がそれを扱っていた時点では、合理的な代替品は見つかりませんでした. ASP.NET Web API がリリースされたので、HttpClientを見てみましょう。それが役立つことを願っています。

于 2012-04-03T18:10:10.617 に答える
8

私はこれがかなり古いことを知っていますが、この問題に遭遇した他の誰かを助けるかもしれない場合に備えて、これをここに置いています. 並列アウトバウンド HTTPS リクエストでも同じ問題に遭遇しました。遊びにはいくつかの問題があります。

最初の問題は、ServicePointManager.DefaultConnectionLimit私が知る限り、接続制限を変更しなかったことです。これを 50 に設定し、新しい接続を作成し、新しい接続のサービス ポイントの接続制限を確認すると、2 と表示されます。そのサービス ポイントで一度 50 に設定すると、最終的に通過するすべての接続に対して機能し、持続するように見えます。そのサービスポイント。

2 番目に遭遇した問題は、スレッドに関するものでした。モノ スレッド プールの現在の実装では、1 秒あたり最大 2 つの新しいスレッドが作成されるようです。まったく同時に開始する多くの並列リクエストを実行している場合、これは永遠です。これに対抗するために、ThreadPool.SetMinThreads をより高い数値に設定してみました。現在のスレッド数と目的の数の間のデルタに関係なく、この呼び出しを行うと、Mono は最大 1 つの新しいスレッドしか作成しないようです。スレッド プールが必要な数のアイドル スレッドになるまで、ループ内で SetMinThreads を呼び出すことにより、これを回避することができました。

後者の問題についてバグを開いたのは、それが意図したとおりに機能していないと最も確信しているためです: https://bugzilla.xamarin.com/show_bug.cgi?id=7055

于 2012-09-11T14:16:03.877 に答える
0

@jake-moshenko がServicePointManager.DefaultConnectionLimit、Mono で変更しても効果がないという意見が正しい場合は、http://bugzilla.xamarin.com/ にバグとして報告してください。

ただし、これを Mono の問題として完全に破棄する前に、いくつかのことを試してみます。

  1. --gc=sgenmono にフラグとして渡すことにより、古い boehm の代わりに SGen ガベージ コレクターを使用してみてください。
  2. 上記で問題が解決しない場合は、Mono 3.2 にアップグレードしてください (ところで、これは SGEN GC にもデフォルト設定されています)。これは、質問してから多くの修正が行われたためです。
  3. 上記で問題が解決しない場合は、独自の Mono (マスター ブランチ) を構築してください。スレッドに関するこの重要なプル リクエストが最近マージされたためです。
  4. 上記で問題が解決しない場合は、このプル リクエストを追加して独自の Mono を構築してください。問題が解決した場合は、プル リクエストに「+1」を追加してください。バグ 7055の修正かもしれません。
于 2013-07-31T22:23:12.867 に答える