C # — Ошибки при выполнении многих одновременных исходящих HTTP-запросов

#c# #.net #linux #http #digital-ocean

#c# #.net #linux #http #digital-ocean

Вопрос:

Я пытаюсь выполнить более 25 Тыс. одновременных исходящих HTTP запросов, которые корректно работают на моем локальном компьютере (работают Windows 10 с 8 ядрами и 16 потоками, с 16 ГБ оперативной памяти), но время ожидания / ошибка при запуске из моей Digital Ocean droplet Ubuntu 20.04.1 LTS (с использованием 2 процессоров и 2 ГБ оперативной памяти).).

Это связано с основным консольным приложением .NET (dotnet) на C #.

  • Моя личная сеть имеет ~300mbps скорость загрузки.
  • У капли есть ~1gbps скорость загрузки.

Задание Droplet работает корректно при ограничении одновременных HTTP-запросов до 5 кб (но начинает давать сбой при попытке с 7,5 кб ) вместо желаемых ~ 25 кб.

Насколько мне сообщила команда Digital Ocean:

  • В droplets не указано максимальное количество исходящих одновременных HTTP запросов.
  • В droplets нет максимального ограничения пропускной способности входящего канала.

Время отклика в Droplet быстрее, поэтому я ожидал бы противоположного поведения.

CURL из капли: СКРУЧИВАНИЕ из капли

CURL с локального компьютера: CURL с локального компьютера


Код состоит из чтения огромной базы данных и генерации пакетов из 25 тыс. элементов и одновременного запроса для каждого, затем выполнения некоторых других операций и обновления этих записей.

Код запроса:

 public static class HttpUtils
{
  private static readonly HttpClient client = new HttpClient();

  public static async Task GetThing(string id)
  {
    try
    {
      var response = await client.GetAsync($"https://api.example.com/{id}");
      Console.WriteLine($"Success {id}");
    }
    catch (Exception ex)
    {
      Console.WriteLine($"Failed request {id}:n{ex.Message}");
    }
  }
}
  

Затем я выполняю пакеты:

 var tasks = batch.Select(thing => HttpUtils.GetThing(thing.id));
await Task.WhenAll(tasks);
  

И эти ошибки появляются через некоторое время выполнения:

 [ERR] Failed request XXXXXXXXX
System.Threading.Tasks.TaskCanceledException: The operation was canceled.
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at collector_utils.HttpUtils.GetThing(String id) in /root/development/foo/bar/HttpUtils.cs:line 20
  

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

Может ли быть так, что, поскольку у меня меньше потоков, доступных в droplet, и я ставлю в очередь тысячи запросов, счетчик времени ожидания запускается во время очереди и в конечном итоге истекает время ожидания тех, которые еще не могли быть обработаны?

Комментарии:

1. at this point I don't know what else to try Можете ли вы вместо этого ограничить до 5 КБ за раз?

2. @mjwills Да, но я бы не хотел, поскольку в API, который я использую, реализовано регулирование на основе времени, поэтому мне нужно действовать как можно быстрее, чтобы избежать этого.

3. Если вы работаете локально на WSL — возникает ли у вас такая же проблема? Какой конкретный droplet вы используете?

4. Console.WriteLine общеизвестно медленная операция (поскольку она блокируется). Имеет ли значение их удаление?

5. @Lee Я выполнил пару тестов, обновив до большего количества потоков и оперативной памяти, проверив время ожидания, а затем вернувшись к другой конфигурации. Поэтому я счел это ответом.