Проблема с производительностью сервера ASP.NET Core 2.2 Kestrel

Я столкнулся с проблемой производительности сервера Kestrel. У меня есть следующий сценарий:

    TestClient(JMeter) -> DemoAPI-1(Kestrel) -> DemoAPI-2(IIS) 

Я пытаюсь создать пример приложения, которое могло бы получать содержимое файла по запросу. TestClient (100 потоков) запрашивает DemoAPI-1, который, в свою очередь, запрашивает DemoAPI-2. DemoAPI-2 считывает фиксированный файл XML (максимум 1 МБ) и возвращает его содержимое в качестве ответа (в производстве DemoAPI-2 не будет подвергаться воздействию внешнего мира).

Когда я протестировал прямой доступ из TestClient -> DemoAPI-2, я получил ожидаемый результат (хороший), который выглядит следующим образом:

  1. Среднее: 368 мс
  2. Минимум: 40 мс
  3. Максимум: 1056 мс
  4. Пропускная способность: 40,1/сек

Но когда я попытался получить к нему доступ через DemoAPI-1, я получил следующий результат:

  1. Среднее: 48232 мс
  2. Минимум: 21095 мс
  3. Максимум: 49377 мс
  4. Пропускная способность: 2,0/сек

Как видите, разница огромная. Я не получаю даже 10% пропускной способности DemoAPI-2. Мне сказали, что пустельга более эффективна и быстра по сравнению с традиционным IIS. Кроме того, поскольку нет проблем с прямым доступом, я думаю, что мы можем устранить возможную проблему с DemoAPI-2.

※Код DemoAPI-1:

string base64Encoded = null;
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var response = await this.httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false);

            if (response.StatusCode.Equals(HttpStatusCode.OK))
            {
                var content = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
                base64Encoded = Convert.ToBase64String(content);
            }
return base64Encoded;

※Код DemoAPI-2:

[HttpGet("Demo2")]
    public async Task<IActionResult> Demo2Async(int wait)
    {
        try
        {
            if (wait > 0)
            {
                await Task.Delay(wait);
            }
            var path = Path.Combine(Directory.GetCurrentDirectory(), "test.xml");
            var file = System.IO.File.ReadAllText(path);
            return Content(file);
        }
        catch (System.Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }

Некоторая дополнительная информация:

  1. Оба API являются асинхронными.
  2. Оба API размещены в разных экземплярах EC2 (C5.xlarge Windows Server 2016).
  3. DemoAPI-1 (пустельга) — это автономный API (без обратного прокси-сервера).
  4. TestClient(jMeter) настроен на 100 потоков для этого тестирования.
  5. На данный момент никакая другая конфигурация для сервера пустельги не выполняется.
  6. На данный момент нет фильтра действий, промежуточного программного обеспечения или ведения журнала, которые могли бы повлиять на производительность.
  7. Связь осуществляется с использованием SSL на порту 5001.
  8. Параметр ожидания для DemoAPI2 на данный момент установлен на 0.
  9. Загрузка процессора DEMOAPI-1 не превышает 40%.

Практически невозможно сказать, где у вас узкое место, это можете понять только вы сами. Я бы предложил запустить все это локально и использовать что-то вроде dotTrace, чтобы увидеть, где код тратит больше всего времени.

DavidG 31.05.2019 08:57
Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
0
1
1 085
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

ДЕМОАПИ-1 выполняет неасинхронное чтение потоков:

var bytes = stream.Read(read, 0, DataChunkSize);

while (bytes > 0)
{
  buffer += System.Text.Encoding.UTF8.GetString(read, 0, bytes);
  // Replace with ReadAsync
  bytes = stream.Read(read, 0, DataChunkSize);
}

Это может быть проблемой с пропускной способностью при большом количестве запросов.

Кроме того, я не совсем понимаю, почему вы не тестируете один и тот же код с IIS и Kestrel, я предполагаю, что вам нужно вносить только изменения в среду, а не в код.

Спасибо, что указали на это. Цель обоих API различна. DemoAPI-1 — это кросс-платформенный API, где DemoAPI-2 — API для Windows. Я не сравниваю Kestrel с IIS, моя цель — выяснить причину, по которой Kestrel API такой медленный, и исправить ее. Я добавил показатели производительности DemoAPI-2 только для того, чтобы доказать, что API чтения файлов, размещенный на IIS, не медленный.

JustAProgrammer 31.05.2019 07:35
Ответ принят как подходящий

Проблема была связана с исчерпанием портов HttpClient. Мне удалось решить эту проблему с помощью IHttpClientFactory. Следующая статья может помочь тем, кто сталкивается с подобной проблемой.

https://www.stevejgordon.co.uk/httpclient-creation-and-disposal-internals-should-i-dispose-of-httpclient

Другие вопросы по теме