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