我有一个调用另一个REST服务的REST服务。两者都使用MVC 4 WebAPI并调用它们工作正常,直到我把它放在负载下。简化的代码类似于:
public HttpResponseMessage Get()
{
var url = WebHelpers.CreateUrl(Request, "EmployeesGet");
var client = new HttpClient();
var response = client.GetAsync(url).Result;
var retResp = new HttpResponseMessage();
retResp.Content = response.Content;
return retResp;
}
WebHelper.CreateUrl
构建端点网址。
当我加载时,模拟了100个用户,我得到了大约16,000个请求,并且我得到了套接字异常:
SocketException无法执行对套接字的操作,因为系统缺少足够的缓冲区空间或者队列已满;
这会占用我的电脑的网络堆栈,直到我重置IIS。
我想也许我需要更积极主动地进行清理工作,所以我处理HttpClient
没有任何效果。然后我想我需要处理从端点获得的响应,因为一旦我得到了内容,我就不再需要它了。奇怪的是,我得到一个异常,说不能引用被处置的对象。这来自MVC框架。例外情况如下:
[ObjectDisposedException:无法访问已处置的对象。 对象名:'System.Net.Http.StreamContent'。] System.Web.Http.WebHost.HttpControllerHandler.EndProcessRequest(IAsyncResult result)+49019 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+ 469 System.Web.HttpApplication.ExecuteStep(IExecutionStep step,Boolean& completedSynchronously)+375
如果我返回一个流或只是内容工作正常,但我无法更改响应的状态代码或将任何其他元数据添加到响应中。
那么从Get方法返回响应的最佳方法是什么,该方法已从另一个REST服务调用中接收到内容。我不想反序列化/序列化,我真的希望能够在响应中添加一些数据。
更新:在进行负载测试时查看资源监视器,我看到连接堆叠起来了。看起来,我无法肯定地说,但似乎从Get()
内部调用端点并未释放连接。
答案 0 :(得分:2)
我建议尝试向控制器注入预先创建的HttpClient实例,并在请求中重复使用它。当HttpClient被丢弃时,它会关闭并尝试关闭底层连接。从我记得查看HttpClient源代码开始,每次创建新的HttpClient实例时都会打开一个新连接。
答案 1 :(得分:1)
一些事情
.Result
。这可能是您性能问题的一部分。因为您正在执行异步操作,所以应该通过返回Task<HttpResponseMessage>
并安排将内部服务调用的结果转换为外部调用主体的延续来使您的操作方法为异步。HttpContent
复制到外部调用的结果中。您可能想尝试读取内部流并将其复制到新的外部流中。