3

Martin Fowler (リンク)のパターンに基づいて、HTTP フロント コントローラーを開発しています。私の場合、コントローラーには次の責任があります。 - カプセル化されたデータをアンマーシャリングする - リクエストを承認する - ロギング - リクエストを別のサーバーに中継/転送する

次の可能な解決策が思い浮かびました: - (同期) IHttpHandler、WebClient または HttpWebRequest クラスで要求を転送する - (非同期) IHttpListener (非 IIS ソリューション) - (非同期) IHttpAsyncHandler

理想的な状況は、FC が CPU を消費することなく多数の同時要求 (>10000 TPS) を処理できることです。

ソリューションをテストするために、リクエストを行う 3 つのクライアント、中央に位置するフロント コントローラー、および FC によって渡されたリクエストに応答する 2 つのサーバーを持つ小さなフレームワークを作成しました。フレームワークは 3 つのシナリオのベンチマークを行います。最初に小さなペイロードで高速な応答をテストし、次に大きなペイロード (> 100KB) で高速な応答をテストし、最後に遅い応答 (>3 秒) と小さなペイロードでテストします。

同期 HTTP ハンドラーを使用した最後のテストでは、1 秒あたりのトランザクション数 (TPS) が極端に低くなりました (<25 TPS)。私の推測では、これはハンドラーが応答を待っているときにスレッドをブロックするためです。この問題を克服するために、非同期ハンドラーの実装を開始しました (以下のコードを参照)。問題は、単純に機能しないことです。

頭に浮かんだ最後の (テストされていない) 解決策は、HttpListener クラスを使用することです。これは、同時実行性をきめ細かく制御できる、より軽量なソリューションであると推測しています。José F. Romaniello (リンク) による RX フレームワークを使用した実装例を見てきました。

私の質問は、なぜハンドラーコードが機能しないのですか?これが最も効率的な方法ですか? または、HttpListenerソリューションを支持する必要があります。

非同期 HTTP ハンドラ コード:

public class ForwardRequestHandler : IHttpAsyncHandler
{
    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        var uri = GetForwardUriFor(context.Request.Url.PathAndQuery);

        var proxy = HttpWebRequest.Create(uri) as HttpWebRequest;
        return proxy.BeginGetResponse(new AsyncCallback(EndProcessRequest), new ForwardedRequestContext(context, proxy));
    }

    public void EndProcessRequest(IAsyncResult result)
    {
        var proxy = result.AsyncState as ForwardedRequestContext;
        proxy.TransferResponse(result);
    }

    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        throw new NotSupportedException();
    }

    private Uri GetForwardUriFor(string path)
    {
        var loadbalancer = new RoundRobinLoadBalancer();
        var endpoint = loadbalancer.GetRandomEndPoint();

        return new Uri(
            string.Format("http://{0}{1}", endpoint, path)
        );
    }
}

public class ForwardedRequestContext
{
    private readonly HttpContext context;
    private readonly HttpWebRequest forwarder;

    public ForwardedRequestContext(HttpContext context, HttpWebRequest forwarder)
    {
        this.context = context;
        this.forwarder = forwarder;
    }

    public void TransferResponse(IAsyncResult ar)
    {
        var response = GetResponse();

        var result = forwarder.EndGetResponse(ar);
        response.StatusCode = 200;
        response.ContentType = result.ContentType;
        response.AddHeader("Content-Length", result.ContentLength.ToString());

        result.GetResponseStream().CopyTo(response.OutputStream);
        response.Flush();

        result.Close();
    }

    private HttpResponse GetResponse()
    {
        return context.Response;
    }
}
4

2 に答える 2

0

これに対する1つの可能な解決策は、ARRを使用して転送を行うことです。

Azureでこれを行う例は次のとおりです。

https://github.com/richorama/AzureARR

于 2012-05-04T10:23:56.237 に答える