У меня есть API, который должен вызывать параллельно 4 HttpClients с поддержкой параллелизма 500 пользователей в секунду (все они вызывают API одновременно)
Должен быть строгий тайм-аут, позволяющий API вернуть результат, даже если не все вызовы HttpClients вернули значение.
Конечные точки являются внешними сторонними API, и я не могу их контролировать и не знаю кода.
Я провел обширное исследование по этому вопросу, но даже если многие решения работают, мне нужно то, которое потребляет меньше ресурсов ЦП, поскольку у меня небольшой серверный бюджет.
Пока я придумал это:
var conn0 = new HttpClient
{
Timeout = TimeSpan.FromMilliseconds(1000),
BaseAddress = new Uri("http://endpoint")
};
var conn1 = new HttpClient
{
Timeout = TimeSpan.FromMilliseconds(1000),
BaseAddress = new Uri("http://endpoint")
};
var conn2 = new HttpClient
{
Timeout = TimeSpan.FromMilliseconds(1000),
BaseAddress = new Uri("http://endpoint")
};
var conn3 = new HttpClient
{
Timeout = TimeSpan.FromMilliseconds(1000),
BaseAddress = new Uri("http://endpoint")
};
var list = new List<HttpClient>() { conn0, conn1, conn2, conn3 };
var timeout = TimeSpan.FromMilliseconds(1000);
var allTasks = new List<Task<Task>>();
//the async DoCall method just call the HttpClient endpoint and return a MyResponse object
foreach (var call in list)
{
allTasks.Add(Task.WhenAny(DoCall(call), Task.Delay(timeout)));
}
var completedTasks = await Task.WhenAll(allTasks);
var allResults = completedTasks.OfType<Task<MyResponse>>().Select(task => task.Result).ToList();
return allResults;
Я использую WhenAny и две задачи, одну для вызова, одну для тайм-аута. Если задача вызова опаздывает, другая все равно возвращается.
Теперь этот код работает отлично, и все асинхронно, но мне интересно, есть ли лучший способ добиться этого.
Каждый отдельный вызов этого API создает множество потоков, и при 500 одновременных пользователях требуется в среднем 8 (восемь) D3_V2 4-ядерные машины Azure, что приводит к сумасшедшим расходам, и чем выше тайм-аут, тем выше загрузка ЦП.
Есть ли лучший способ сделать это, не используя так много ресурсов ЦП (возможно, Parallel Linq лучше, чем этот)?
Достаточно ли одного тайм-аута HttpClient, чтобы остановить вызов и вернуться, если конечная точка не ответит вовремя, без необходимости использовать вторую задачу в WhenAny
?
ОБНОВЛЕНИЕ:
- Конечные точки являются сторонними API, я не знаю кода и не имею никакого контроля, вызов выполняется в JSON и возвращает JSON или строку.
- Некоторые из них время от времени отвечают через 10+ секунд или застревают и работают очень медленно, поэтому тайм-аут должен освободить потоки и вернуться, даже если с частичными данными от другого, который вернулся вовремя.
- Кэширование возможно, но только частично, поскольку данные постоянно меняются, например, акции и торговля валютой в режиме реального времени.