首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用IHttpAsyncHandler高效地转发HTTP请求

使用IHttpAsyncHandler高效地转发HTTP请求
EN

Stack Overflow用户
提问于 2012-03-21 15:34:54
回答 2查看 2.6K关注 0票数 3

我正在开发一个基于Martin Fowler (link)模式的HTTP前端控制器。在我的例子中,控制器有以下职责:-解组封装的数据-授权请求-日志记录-中继/转发请求到另一个服务器

想到了以下可能的解决方案:-(同步) IHttpHandler,使用WebClient或HttpWebRequest类转发请求-(异步) IHttpListener (非IIS解决方案)-(异步) IHttpAsyncHandler

理想的情况是FC可以处理大量的并发请求(>10000 TPS),而不会消耗CPU。

为了测试解决方案,我创建了一个小框架,其中有3个客户端发出请求,一个前端控制器位于中间,2个服务器响应FC传递的请求。该框架对3个场景进行了基准测试,首先是使用小负载的快速响应测试,其次是大负载(> 100KB)的快速响应测试,最后是慢响应(>3秒)和小负载的测试。

使用同步HTTP处理程序进行最后一次测试时,每秒事务处理量(TPS)降到了最低点(<25TPS)。我猜测这是由于处理程序在等待响应时阻塞了线程。为了解决这个问题,我已经开始实现一个异步处理程序(参见下面的代码)。问题是,它很简单,不起作用。

我想到的最后一个(未经测试的)解决方案是使用HttpListener类。猜测这是一个更轻量级的解决方案,具有细粒度的并发控制。我见过一个使用Jos F.Romaniello (link)的RX框架的示例实现。

我的问题是,为什么处理程序代码不能工作?这是最有效的方法吗?或者我应该支持HttpListener解决方案。

异步HTTP处理程序代码:

代码语言:javascript
复制
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;
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-04 18:23:56

一种可能的解决方案是使用ARR为您进行转发。

在Azure上有一个这样做的例子:

https://github.com/richorama/AzureARR

票数 0
EN

Stack Overflow用户

发布于 2012-11-28 05:12:41

return proxy.BeginGetResponse(new AsyncCallback(EndProcessRequest), ...中,您创建了一个新的回调,ASP.net不会得到请求结束的通知,因此它不能停止处理请求(这至少是我从许多并发请求中观察到的)。因此,使用传入的回调作为参数。

代码语言:javascript
复制
return proxy.BeginGetResponse(cb, ...

干杯

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9800347

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档