我正在开发一个基于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处理程序代码:
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;
}
}发布于 2012-05-04 18:23:56
发布于 2012-11-28 05:12:41
在return proxy.BeginGetResponse(new AsyncCallback(EndProcessRequest), ...中,您创建了一个新的回调,ASP.net不会得到请求结束的通知,因此它不能停止处理请求(这至少是我从许多并发请求中观察到的)。因此,使用传入的回调作为参数。
return proxy.BeginGetResponse(cb, ...干杯
https://stackoverflow.com/questions/9800347
复制相似问题