Несколько запросов HTTP вызывают тайм-аут клиента HTTP - PullRequest
3 голосов
/ 01 февраля 2020

У меня есть приложение, которое отправляет 500 HTTP-запросов асинхронно. Все запросы, обработанные после 15 секунд, завершаются неудачно из-за тайм-аута на HTTP-клиенте, даже , когда запрошенная конечная точка уже вернула 200 OK.

Код очень прост. Здесь мы берем кусок запросов (500) и выполняем их асинхронно. Следует отметить, что нижеприведенная функция - это функция Azure, выполняемая в плане потребления.

    public async Task RunBatch(List<Request> requests)
    {
        if (requests != null && requests .Count > 0)
        {
            var tasks = new Task[requests.Count];
            var i = 0;
            foreach (var request in requests)
            {
                var request = new HttpRequestMessage(HttpMethod.Post, new Uri(request.Url));
                request.Content = new StringContent(request.BodyString, Encoding.UTF8, "application/json");
                tasks[i] = _httpClient.SendAsync(request);
                i++;
            }

            await Task.WhenAll(tasks);
        }
    }

В моем конструкторе существует следующий код

_httpClient = new HttpClient();
_httpClient.Timeout = new TimeSpan(0, 0, 15); // 15 seconds

Вот журналы от Azure.

enter image description here enter image description here

Я бы хотел, чтобы время ожидания каждого запроса составляло 15 секунд. Однако мне нужно, чтобы он давал точный код ответа всякий раз, когда мой сервер приступает к обработке ожидаемого запроса. Возможно ли это?

Следует отметить: при более высоком тайм-ауте Http (1 мин) все запросы выполняются успешно.

Ответы [ 5 ]

3 голосов
/ 07 февраля 2020

Лично я думаю, что попытка выдать 500 одновременных запросов всегда будет подвержена ошибкам. Вы упоминаете, что делаете это асинхронно, но на самом деле в вашем коде не так много асинхронности, так как вы запускаете 500 «горячих» задач и ждете, пока они завершатся sh.

Я бы использовал семафор, чтобы контролировать, сколько запросов можно сделать одновременно. Возможно, вам придется поиграть с числами, чтобы найти нужное место.

Следующий код хорошо работает в LINQPad (хотя bing быстро замечает нечетное количество запросов и начинает добавлять CAPTCHA на страницу):

async Task Main()
{
    var httpClient = new HttpClient();
    var urls = Enumerable.Range(1, 500).Select(e => "https://www.bing.com/").ToList();

    // 10 concurrent requests - tweak this number
    var semaphore = new SemaphoreSlim(10, 10);

    var tasks = urls.Select(u => MakeRequest(u, semaphore, httpClient));

    var allResponses = await Task.WhenAll(tasks);

    // Do something with allResponses
}

private async Task<string> MakeRequest(string url, SemaphoreSlim semaphore, HttpClient httpClient)
{
    try
    {
        await semaphore.WaitAsync();
        var request = new HttpRequestMessage(HttpMethod.Get, new Uri(url));
        var response = await httpClient.SendAsync(request);

        // Add an optional delay for further throttling:
        //await Task.Delay(TimeSpan.FromMilliseconds(100));

        return await response.Content.ReadAsStringAsync();
    }
    finally
    {
        semaphore.Release();
    }
}
2 голосов
/ 07 февраля 2020

Есть несколько проблем с HttpClient.

Например:

  1. HttpClient является одноразовым: использование HttpClient с оператором using не лучший выбор, поскольку даже при удалении объекта HttpClient базовый сокет не сразу выпущен и может вызвать серьезную проблему под названием «исчерпание сокетов». Для получения дополнительной информации об этой проблеме, Вы неправильно используете httpclient и дестабилизируете ваше программное обеспечение

  2. HttpClient предназначен для однократного создания и повторного использования в течение всей жизни приложение. Создание класса HttpClient для каждого запроса приведет к исчерпанию количества сокетов, доступных при больших нагрузках. Эта проблема приведет к ошибкам SocketException. Возможные подходы к решению этой проблемы основаны на создании объекта HttpClient как singleton или stati c.

  3. HttpClient, который можно использовать при его использовании в качестве объекта singleton или stati c. В этом случае, singleton или stati c HttpClient не учитывает изменения DNS. Для получения дополнительной информации: Singleton HttpClient не учитывает изменения DNS

Чтобы устранить указанные выше проблемы и упростить управление экземплярами HttpClient, NET В Core 2.1 появился новый HttpClientFactory .

Что такое HttpClientFactory:

  1. Предоставляет централизованное расположение для именования и настройки логических объектов HttpClient. Например, вы можете настроить клиент (агент службы), который предварительно настроен для доступа к указанному микросервису c.
  2. Кодировать концепцию исходящего промежуточного программного обеспечения через делегирование обработчиков в HttpClient и реализацию промежуточного программного обеспечения на основе Polly для принятия Преимущество политик Polly для обеспечения отказоустойчивости.
  3. HttpClient уже имеет концепцию делегирования обработчиков, которые могут быть связаны друг с другом для исходящих HTTP-запросов. Вы регистрируете HTTP-клиенты на заводе и можете использовать обработчик Polly для использования политик Polly для Retry, CircuitBreakers и т. Д.
  4. Управление временем жизни HttpClientMessageHandlers, чтобы избежать упомянутых проблем / проблем, которые могут возникнуть при управлении Время жизни HttpClient самостоятельно.

Для получения более подробной информации перейдите по этой ссылке: Используйте HttpClientFactory для реализации устойчивых HTTP-запросов

Вы также можете использовать RestSharp библиотека для отправки любых запросов. Для более http://restsharp.org/

Ссылочные ресурсы:

  1. https://josefottosson.se/you-are-probably-still-using-httpclient-wrong-and-it-is-destabilizing-your-software/
  2. https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
  3. https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
  4. https://github.com/dotnet/runtime/issues/18348
1 голос
/ 07 февраля 2020

Несколько вещей, которые я бы проверял:

  • Вместо того, чтобы каждый раз использовать новый HttpClient, используйте HttpClientFactory, чтобы избежать издержек конструкции HttpClient и исчерпания ресурсов. портов.

  • Вы уверены, что Bing не ограничивает скорость? Попробуйте настроить таргетинг на удаленный сервер под вашим контролем.

  • Попробуйте ограничить параллелизм ваших запросов с помощью SemaphoreSlim или библиотеки параллелизма.

0 голосов
/ 05 февраля 2020

Кажется, вы отправляете запрос в поисковую систему Bing, верно? Если я прав, у вас есть другая проблема. Поиск в Bing может не разрешать запросы ботов. Поэтому блокировать запросы bing на другой сервис или API.

0 голосов
/ 01 февраля 2020

Попробуйте увеличить лимит подключений по умолчанию:

ServicePointManager.UseNagleAlgorithm = true;
ServicePointManager.Expect100Continue = true;
ServicePointManager.DefaultConnectionLimit = <number>;
...