#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 быстрее, поэтому я ожидал бы противоположного поведения.
Код состоит из чтения огромной базы данных и генерации пакетов из 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 Я выполнил пару тестов, обновив до большего количества потоков и оперативной памяти, проверив время ожидания, а затем вернувшись к другой конфигурации. Поэтому я счел это ответом.