Как стать автором
Обновить

Занимательная задача с микросервисами в .NET

Время на прочтение3 мин
Количество просмотров8.8K

Необходимо реализовать возможность приёма транзакций от разных клиентов для процессинга и дальнейшей отправки в разные банки. Клиенты могут присылать как равномерно (например, по 1шт в секунду), так и большими пачками (1000шт каждый час или 10000 раз в день), банки обрабатывают транзакции последовательно.

Для простоты интеграции необходимо использовать REST API для приёма транзакций

Необходимо исключить ситуации, когда:

Тысячи клиентов по несколько транзакции ожидают двух, у которых по 10000 транзакций

Несколько клиентов по 10000 ждут тысячи клиентов по несколько транзакций.


Ок, нужно реализовать сервис который обрабатывает транзакции

Первым делом, для клиентов у которых меньше 100 транзакций в запросе использовать отдельный инстанс сервиса, масштабировать горизонтально.

[Route("api/[controller]")]
[ApiController]
public class ProcessController : ControllerBase
{
    [HttpPost("Queue")]
    public async Task<IActionResult> Queue([FromBody] RequestDTO request)
    {
        // Что-то вроде балансировки нагрузки
        var requestUri = request.TransactionsCount < 100
            ? $"http://instance1:81/api/Process/Queue"
            : $"http://instance2:81/api/Process/Queue";

        HttpClient client = new HttpClient();
        var result = await client.PostAsJsonAsync(requestUri, request); 
        var content = await result.Content.ReadAsStringAsync();
        return Ok(content);
    }
}

Да, но в случае, когда есть 3 клиента (Клиент 1: 10000 транзакций), (Клиент 2: 1000 транзакций), (Клиент 3: 100 транзакций) третий клиент будет ожидать пока выполнятся все 11000 транзакций первых двух клиентов

Может обрабатывать сперва запросы у которых меньше транзакций?

Тогда в случае, когда 1000 клиентов (Клиент 1: 10000 транзакций), (Клиент 2-500: 1000 транзакций), (Клиент 501 - 1000: 100 транзакций), Клиент 1 будет ожидать пока обработаются все мелкие запросы. Вариант увеличить мощность машины в котором инстанс для больших запросов, масштабировав вертикально тоже отметается.

Тогда придется добавить все запросы в очередь (или группировать по клиентам, или по другому параметру) и выполнять транзакции по очереди с каждого запроса. Это, по моему мнению, самый справедливый вариант для клиентов, так как клиент не просто ждет пока дойдет его очередь, а постепенно получает callback от выполненных транзакций

if (Requests.Any())
{
    // С каждого запроса выполняем одну транзакцию
    List<Task> tasks = new List<Task>();
    foreach(var request in Requests.ToList())
    {
        // имитируем обработку транзакции
        tasks.Add(TransactionProcess());
        request.TransactionsCount--;
        // имитируем callback
        logger.LogCritical($"[Client: {request.Client}] left {request.TransactionsCount} transactions");
        if(request.TransactionsCount == 0)
        {
            // Если все транзакции клиента выполнены, удаляем запрос из очереди
            Requests.Remove(request);
        }
    }
    // Выполняем транзакции одного цикла параллельно
    await Task.WhenAll(tasks);
}
3 запроса по 1, 3 и 6 транзакций и порядок их выполнения
3 запроса по 1, 3 и 6 транзакций и порядок их выполнения

А потом пакуем приложение с помощью docker compose. Результат тут

Тут мы можем увидеть, что для каждого клиента выполняется по одной транзакции:

3 клиента по 10000, 1000 и 500 транзакций в одном запросе в контейнере instance2-1
3 клиента по 10000, 1000 и 500 транзакций в одном запросе в контейнере instance2-1

А тут, то что "Load balancer" перенаправляет запросы с менее 100 транзакциями в первый инстанс:

Запрос четвертого клиента, у которого всего 90 транзакций (меньше 100) обрабатывается в отдельном контейнере instance1-1
Запрос четвертого клиента, у которого всего 90 транзакций (меньше 100) обрабатывается в отдельном контейнере instance1-1

Предлагайте как еще можно улучшить решение. Также предлагайте другие задачи на тему микросервисов

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 8: ↑2 и ↓6-2
Комментарии31

Публикации

Истории

Работа

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
26 октября
ProIT Network Fest
Санкт-Петербург
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань