ASP.NET Web API 2 - StreamContent чрезвычайно медленный
Мы перенесли проект из WCF в Web API (SelfHost), и во время процесса мы заметили огромный спад при обслуживании веб-приложения. Теперь 40-50 секунд против 3 секунд ранее.
Я воспроизвел проблему в простом консольном приложении, добавив различные Nacet Pacakges для AspNet.WebApi и OwinSelfHost со следующим контроллером:
var stream = new MemoryStream();
using (var file = File.OpenRead(filename))
{
file.CopyTo(stream);
}
stream.Position = 0;
var response = Request.CreateResponse(System.Net.HttpStatusCode.OK);
/// THIS IS FAST
response.Content = new ByteArrayContent(stream.ToArray());
/// THIS IS SLOW
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue(System.Web.MimeMapping.GetMimeMapping(filename));
response.Content.Headers.ContentLength = stream.Length;
Как видно из кода, единственным отличием является использование StreamContent (slooooow) и ByteArrayContent.
Приложение размещено на машине Win10 и доступно с моего ноутбука.
Fiddler показывает, что для получения одного 1 МБ файла с сервера на мой ноутбук с использованием StreamContent требуется 14 секунд, а ByteArrayContent меньше 1 с.
Также обратите внимание, что полный файл считывается в память, чтобы показать, что единственным отличием является класс содержимого.
Странная вещь заключается в том, что кажется, что ее передача сама по себе медленная. Сервер отвечает на заголовки быстро/немедленно, но для получения данных требуется много времени, как показано в информации о времени Fiddler:
GotResponseHeaders: 07:50:52.800
ServerDoneResponse: 07:51:08.471
Полная информация о времени:
== TIMING INFO ============
ClientConnected: 07:50:52.238
ClientBeginRequest: 07:50:52.238
GotRequestHeaders: 07:50:52.238
ClientDoneRequest: 07:50:52.238
Determine Gateway: 0ms
DNS Lookup: 0ms
TCP/IP Connect: 15ms
HTTPS Handshake: 0ms
ServerConnected: 07:50:52.253
FiddlerBeginRequest:07:50:52.253
ServerGotRequest: 07:50:52.253
ServerBeginResponse:07:50:52.800
GotResponseHeaders: 07:50:52.800
ServerDoneResponse: 07:51:08.471
ClientBeginResponse:07:51:08.471
ClientDoneResponse: 07:51:08.471
Overall Elapsed: 0:00:16.233
Кто-нибудь знает, что происходит под капотом, который может объяснить разницу в поведении?
Ответы
Ответ 1
Решением моей проблемы для самостоятельного хостинга OWIN был размер буфера StreamContent. По умолчанию конструктор StreamContent использует значение по умолчанию 0x1000, 4Kb. В гигабитной сети передача 26 Мб файла занимает ~ 7 минут, чтобы завершить со скоростью ~ 60 Кбит/с.
const int BufferSize = 1024 * 1024;
responseMessage = new HttpResponseMessage();
responseMessage.Content = new StreamContent(fileStream, BufferSize);
Изменение значения bufferSize до 1Mb займет всего несколько секунд, чтобы завершить загрузку.
[EDIT] В StreamContent SerializeToStreamAsync делает StreamToStreamCopy, в соответствии с этой ссылкой производительность будет отличаться. Подходящее значение, вероятно, составляет 80K.
Ответ 2
У меня такая же проблема, и я думаю, что это связано с самим хостингом Owin. Я просто создал образец приложения Asp.net и разместил его на IIS. В этом случае он работал, как ожидалось.
Результаты моей тестовой системы при загрузке файла размером 80 МБ:
- с Streamcontent и SelfHosting: ~ 20 минут
- с ByteArrayContent и Selfhosting: < 30 секунд
- с Streamcontent и IIS Hosting: < 30 секунд
Либо есть параметр конфигурации в ASP.net, который мне не хватает в моем самообслуживаемом проекте, либо есть ошибка в коде самообслуживания owin, я думаю.
Ответ 3
Когда вы выполняете проекты, попробуйте перейти от отладки к выпуску. это короткая съемка, которая бы немного увеличила производительность