Серьезная задержка с использованием HttpClient в сочетании с NServiceBus

Я делаю интеграцию POC, используя NServiceBus. Эта интеграция запускает уведомления API, когда что-то происходит.

Все это работает, но серьезные проблемы с производительностью возрастают при выполнении параллельных HTTP-запросов.

У меня настроена конечная точка, которая выполняет одно: отправка запроса (уведомления) json в REST API.

Моя настройка:

Конечная точка (каркас 4.6.1) имеет 1 статический HttpClient, который инициализируется только один раз при запуске программы:

internal static void Intitialize()
        {
            ServicePointManager.DefaultConnectionLimit = 100;
            var apiSettings = NotificationEngineManager.GetInterfaceSettings()?.API;
            NotificationClient = new HttpClient();
            NotificationClient.Timeout = TimeSpan.FromSeconds(45);
            if (!string.IsNullOrEmpty(apiSettings.UserName))
            {
                var byteArray = Encoding.ASCII.GetBytes($"{apiSettings.UserName}:{apiSettings.Password}");
                NotificationClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
            }
        }

        internal static HttpClient NotificationClient { get; set; }

Мой обработчик отвечает за размещение запросов:

   public async Task Handle(EventRegistered message, IMessageHandlerContext context)
            {
                var apiSettings = NotificationEngineManager.GetInterfaceSettings()?.API;
                if (apiSettings == null)
                {
                    throw new BusinessException("No valid API settings found");
                }

                JsonSerializerSettings settings = new JsonSerializerSettings();
                settings.NullValueHandling = NullValueHandling.Ignore;
                settings.DateFormatString = "s";
                settings.Converters.Add(new StringEnumConverter { });


                try
                {
                    var jsonRequest = JsonConvert.SerializeObject(message.Notification, settings);
                    var response = await HttpClients.NotificationClient.PostAsync(apiSettings.Endpoint, new StringContent(jsonRequest, Encoding.UTF8, "application/json"));
                    response.EnsureSuccessStatusCode();
                }
                catch (TaskCanceledException)
                {
                    throw new Exception("Notifiaction Request timed out.");
                }

                await context.Publish(new NotificationSent(message, DateTime.Now)).ConfigureAwait(false);

}

Эта проблема:

Конечная точка NServiceBus обрабатывает 10 сообщений одновременно, что означает 10 запросов HTTP post одновременно.

API остальных занимает около 0,2 с, чтобы ответить на 1 сообщение. Но одновременный запуск 10 http-запросов занимает около 35 секунд. Все запросы начинаются одновременно, но также и заканчиваются в одно и то же время, что примерно через 35 секунд.

С помощью netstat Команда Я вижу 10 открытых TCP-подключений к API. Таким образом, HttpClient обрабатывает параллельные запросы.

Странно то, что если я установил параллелизм моей конечной точки на 1, то есть запросы http обрабатываются 1 на 1, все 10 запросов были обработаны в течение 2 секунд.

Если я установлю уровень параллелизма моей конечной точки равным 20 или более, время ожидания почти для всех запросов (тайм-аут = 45 с).

То же самое можно воспроизвести, используя HttpWebRequest вместо HttpClient.

Я в недоумении здесь. Что мне не хватает? Похоже, что все запросы ожидают друг друга, либо на клиенте, либо на сервере. Любая помощь очень ценится.

Rest API - это базовый.NET Core API, работающий на ISS (не экспресс).

// POST api/notification
        [HttpPost]
        [Authorize]
        public async Task<IActionResult> Post([FromBody] Notification notification)
        {
            try
            {
                return Accepted();
            }
            catch (Exception ex)
            {

                return BadRequest(ex);
            }

        }

ОБНОВЛЕНИЕ: Журнал на стороне клиента (nservicebus) и на стороне сервера (api). Оба работают в режиме отладки на локальном хосте и легко воспроизводятся.

сторона клиента

    log.Info($"Start request {message.Event.Id.ToString()}");
                    var response = await HttpClients.NotificationClient.PostAsync(apiSettings.Endpoint, new StringContent(jsonRequest, Encoding.UTF8, "application/json"));              
                    response.EnsureSuccessStatusCode();
                    log.Info($"Stop request {message.Event.Id.ToString()}");

2018-04-18 09:05:23.2886 INFO NOTIFY_WO_OUT 8 Start request
2018-04-18 09:05:23.2886 INFO NOTIFY_WO_OUT 10 Start request
2018-04-18 09:05:23.2886 INFO NOTIFY_WO_OUT 5 Start request
2018-04-18 09:05:23.2886 INFO NOTIFY_WO_OUT 2 Start request
2018-04-18 09:05:23.2886 INFO NOTIFY_WO_OUT 4 Start request
2018-04-18 09:05:23.6336 INFO NOTIFY_WO_OUT 6 Start request
2018-04-18 09:05:24.6329 INFO NOTIFY_WO_OUT 9 Start request
2018-04-18 09:05:25.6142 INFO NOTIFY_WO_OUT 1 Start request
2018-04-18 09:05:26.6544 INFO NOTIFY_WO_OUT 7 Start request
2018-04-18 09:05:27.6545 INFO NOTIFY_WO_OUT 3 Start request
2018-04-18 09:05:47.2034 INFO NOTIFY_WO_OUT 5 Stop request
2018-04-18 09:05:47.6285 INFO NOTIFY_WO_OUT 3 Stop request
2018-04-18 09:05:47.9855 INFO NOTIFY_WO_OUT 6 Stop request
2018-04-18 09:05:48.0550 INFO NOTIFY_WO_OUT 9 Stop request
2018-04-18 09:05:48.5226 INFO NOTIFY_WO_OUT 4 Stop request
2018-04-18 09:05:48.5526 INFO NOTIFY_WO_OUT 10 Stop request
2018-04-18 09:05:48.9987 INFO NOTIFY_WO_OUT 8 Stop request
2018-04-18 09:05:49.0347 INFO NOTIFY_WO_OUT 1 Stop request
2018-04-18 09:05:49.0647 INFO NOTIFY_WO_OUT 7 Stop request
2018-04-18 09:05:49.3017 INFO NOTIFY_WO_OUT 2 Stop request

регистрация на стороне сервера. Промежуточное программное обеспечение добавлено в начало конвейера.

2018-04-18 09:05:38.7660 INFO Begin Request 6
2018-04-18 09:05:38.7850 INFO message 6 received
2018-04-18 09:05:38.8150 INFO End Request 6
2018-04-18 09:05:39.4036 INFO Begin Request 9
2018-04-18 09:05:39.4231 INFO message 9 received
2018-04-18 09:05:39.4551 INFO End Request 9
2018-04-18 09:05:39.7172 INFO Begin Request 10
2018-04-18 09:05:39.7512 INFO message 10 received
2018-04-18 09:05:39.7512 INFO Begin Request 8
2018-04-18 09:05:39.7812 INFO End Request 10
2018-04-18 09:05:39.8132 INFO message 8 received
2018-04-18 09:05:39.8302 INFO End Request 8
2018-04-18 09:05:40.0722 INFO Begin Request 1
2018-04-18 09:05:40.1097 INFO message 1 received
2018-04-18 09:05:40.1097 INFO Begin Request 5
2018-04-18 09:05:40.1413 INFO message 5 received
2018-04-18 09:05:40.1703 INFO End Request 1
2018-04-18 09:05:40.1913 INFO End Request 5
2018-04-18 09:05:40.4033 INFO Begin Request 3
2018-04-18 09:05:40.4403 INFO message 3 received
2018-04-18 09:05:40.4563 INFO End Request 3
2018-04-18 09:05:40.5173 INFO Begin Request 7
2018-04-18 09:05:40.5508 INFO message 7 received
2018-04-18 09:05:40.5663 INFO End Request 7
2018-04-18 09:05:41.0100 INFO Begin Request 4
2018-04-18 09:05:41.0470 INFO message 4 received
2018-04-18 09:05:41.0630 INFO End Request 4
2018-04-18 09:05:41.3535 INFO Begin Request 2
2018-04-18 09:05:41.3740 INFO message 2 received
2018-04-18 09:05:41.4080 INFO End Request 2

Просмотр запроса 8. Запрос был инициирован в коде.23. Сервер получил запрос на.39. Таким образом, разрыв составляет 16 секунд.

1 ответ

Решение

Я регистрировал трассировку сети, используя System.Diagnostics и NLog. Это вызывало серьезное падение производительности.

Отключение System.Diagnostics решило мою проблему.

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