簡體   English   中英

使用IHttpAsyncHandler高效轉發HTTP請求

[英]Efficient forwarding HTTP requests with an IHttpAsyncHandler

我正在開發一個基於Martin Fowler( 鏈接 )模式的HTTP前端控制器。 在我的情況下,控制器具有以下職責: - 解組封裝的數據 - 授權請求 - 記錄 - 將請求中繼/轉發到另一台服務器

以下是可能的解決方案: - (同步)IHttpHandler,使用WebClient或HttpWebRequest類轉發請求 - (異步)IHttpListener(非IIS解決方案) - (異步)IHttpAsyncHandler

理想的情況是FC可以處理大量並發請求(> 10000 TPS)而不會燒毀CPU。

為了測試解決方案,我創建了一個小型框架,其中有3個客戶端發出請求,一個位於中間的前端控制器和兩個響應FC傳遞的請求的服務器。 框架基准測試3場景,首先測試具有小有效載荷的快速響應,其次:具有大有效載荷的快速響應(> 100KB),最后是具有慢響應(> 3秒)和小有效載荷的測試。

使用同步HTTP處理程序進行的最后一次測試,每秒事務數(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;
    }
}

return proxy.BeginGetResponse(new AsyncCallback(EndProcessRequest), ...你創建一個新的回調,並且ASP.net沒有得到關於請求結束的通知,因此它無法停止處理thre請求(這至少是這個)我通過許多並發請求觀察到的內容。)因此使用傳入的回調作為參數。

return proxy.BeginGetResponse(cb, ...

干杯

一種可能的解決方案可能是使用ARR為您進行轉發。

這里有一個在Azure上執行此操作的示例:

https://github.com/richorama/AzureARR

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM