Я столкнулся с проблемой производительности сервера Kestrel. У меня есть следующий сценарий:
TestClient(JMeter) -> DemoAPI-1(Kestrel) -> DemoAPI-2(IIS)
Я пытаюсь создать пример приложения, которое могло бы получать содержимое файла по запросу. TestClient (100 потоков) запрашивает DemoAPI-1, который, в свою очередь, запрашивает DemoAPI-2. DemoAPI-2 считывает фиксированный файл XML (максимум 1 МБ) и возвращает его содержимое в качестве ответа (в производстве DemoAPI-2 не будет подвергаться воздействию внешнего мира).
Когда я протестировал прямой доступ из TestClient -> DemoAPI-2, я получил ожидаемый результат (хороший), который выглядит следующим образом:
Но когда я попытался получить к нему доступ через DemoAPI-1, я получил следующий результат:
Как видите, разница огромная. Я не получаю даже 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 выполняет неасинхронное чтение потоков:
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, не медленный.
Проблема была связана с исчерпанием портов HttpClient. Мне удалось решить эту проблему с помощью IHttpClientFactory. Следующая статья может помочь тем, кто сталкивается с подобной проблемой.
Практически невозможно сказать, где у вас узкое место, это можете понять только вы сами. Я бы предложил запустить все это локально и использовать что-то вроде dotTrace, чтобы увидеть, где код тратит больше всего времени.