Привет, Хабр.

Меня зовут Владимир Евсеев, я Senior Java developer, Teamlead в SSP SOFT.

Наша команда приступила к масштабному проекту: системе, обеспечивающей транспортный уровень документооборота банка. Сегодня я расскажу, как мы справились с первым этапом: выстроили магистраль, способную передавать около 150 000 файлов в сутки, или 1,5 терабайта информации. Поделюсь, что получилось и что еще предстоит  довести до совершенства.

Как мы выстроили движение по этой магистрали?

Итак, наша задача звучала так: создать систему, обеспечивающую транспортный уровень документооборота процессинга банка. Звучит уже масштабно, учитывая, что наш клиент — один из крупнейших банков на рынке.

Пару уточняющих вопросов заказчику, и вот уже нарисовалась наша большая проблема: обеспечить передачу  до 150 000 файлов в сутки. Каждые сутки. Всегда.

Что мы предложили в качестве MVP?

Архитектура: микросервисы, общение через Kafka, самые нагруженные сервисы task-manager, agent.

Сервисы:

  • Task-manager — оркестратор операций над файлами. Следит за выполнением всех операций, при необходимости делает повтор, принимает решения о запуске операции.

  • Detector — обходчик, принимает расписание и файл-сервер, на котором мониторит файлы по маске файла. Уведомляет task-manager о появлении нового файла.

  • Agent — занимается исполнением операции над файлом: копирование, переименование, перемещение, удаление.

  • Archive — архиватор, архивирует файл и копирует в MinIO.

  • Notification — отправка уведомлений о состоянии файла на почту.

  • UI — интерфейс системы, реестр правил, включение, отключение, история выполнения.

  • Redis — как кэш системы.

  • Kafka — транспорт системы.

  • MinIO — временное хранилище и архив.

  • Oracle — персистентное хранилище правил и их истории.

Для того что бы выдерживать передачу  до 150 000 файлов, применили Event-driven architecture, все события обрабатываются асинхронно. Самый нагруженный сервис это task-manager. В сутки ему необходимо обрабатывать около 1 миллиона сообщений и кэшировать их в редис. Поэтому для реализации выбрали Project Reactor и реактивный драйвер для Redis от Lettuce (https://lettuce.io/). Для подключения к Kafka и маршрутизации сообщений используем Spring Integration.

Detector построен на Spring Integration, он из коробки позволяет создать flow, который может мониторить файл-сервер на наличие файлов по маске. Мы лишь немного докрутили логику создания flow. А именно: создаем flow по запросу от менеджера, добавили логику с регистрацией flow и поправили обработку исключений.

Если обходчик не может подключится к хосту сервера, то он будет пробовать снова и снова, делаем через события Spring. Spring Integration предоставляет маршрутизацию, нам это важно, потому что есть несколько протоколов (FTP, SMB, SFTP). Еще одним плюсом Spring Integration является то, что он реализует паттерн Control Bus. Это позволяет перезапускать бины в рантайме, а это важно, потому что каждый обходчик — это бин, который запускается по cron-расписанию.

Agent — для управлением ЖЦ операции. Используем Completable Feature — есть возможность остановить таску, это тоже часть нашего функционала. Ну и не забываем про асинхронный подход.

Archive и Notification — ничем не выделяются, поэтому на них останавливаться не будем.

Нагрузочное  тестирование

Эту всю красоту мы не могли не протестить. Развернули standalone конфигурацию и дали нагрузку 300 000 файлов за сутки, т.е. за час система должна перекладывать ~13 000 файлов при среднем размере 10 Мб. Первый прогон показал, что task-manager падает с ошибкой CommandTimeoutException. Это говорит о том, что конфиг клиента сделан не правильно.

Исправили, докрутили пул коннектов, докинули 1 ЦПУ (изначально был 1 ЦПУ) и, о чудо, task-manager начал с бешеной скоростью обрабатывать и сохранять кеш в Redis! Результат 3 000 файлов в час, это примерно 72 000 файлов в сутки при standalone конфигурации. Развернуть кластер из 2-х нод, получаем 144 000 файлов в сутки.

Второй прогон: с менеджером все ок, но теперь падает agent потому что быстро забиваем thread pool, так как task-manager со скоростью звука ддосит агента. При этом система продолжает работать, но очень сильная деградация. Подкрутили настройки агента, ЦПУ, RAM. Результат 4 000 файлов в час, это примерно 96 000 файлов в сутки при standalone конфигурации. Развернуть кластер из 2х нод, получаем примерно 200 000 файлов в сутки.

Третий прогон: настроили кластер из двух нод, дали ту же самую нагрузку, получили 8 000 файлов в час, что доказывает передачу 192 000 файлов в сутки.

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

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

Движемся дальше и работаем над гарантиями по транспортировке файлов. Подмигните в комментах, если интересно.  Будем держать вас в курсе.

Комментарии (13)


  1. net_men
    16.01.2023 10:54
    +1

    что-то вы путаетесь: то 150 тысяч, то 150 миллионов... это немного разные поток.


    1. SSP_blog Автор
      16.01.2023 10:57

      увидел. 150 тысяч, конечно во всех случаях должно быть! Спасибо, сейчас исправлю.


  1. Filex
    16.01.2023 11:16

    Я правильно понял, что все документы кешируются в Redis? А сколько у вас оперативной памяти выделено для кеша?


    1. evseevvd
      16.01.2023 11:24
      +1

      в кеш кладется информация по операциям, не бинарники которые летают. в моменте кеш около 1Гб (это если передавать 150 000 файлов), т.е. оперативки надо минимум 2 Гб (1 Гб системе, 1 Гб редису). И это можно настраивать из сервиса выставляя TTL для ключей.


  1. MasterMentor
    16.01.2023 11:46
    +2

    150 000 файлов в сутки - и это скорость?!

    Да, ладно, ребята. Вот если бы 150 000 файлов в минуту, то, да, ещё можно было бы почитать.

    Но главное: вообще нет никаких данных о скорости каналов передачи/приёма информации, частоте прихода файлов, скорости хранилища файлов, итд.

    Хотя бы какие-то выкладки должны быть, чтобы видеть, что ваше решение с Redis, Kafka, MinIO, Archive, Agent, Detector, Task-manager имеет преимущество над скриптом в 20 строк, кладущим входящие файлы в папку файловой системы и отдающим их, например, через curl.


    1. evseevvd
      16.01.2023 12:37
      -2

      Да, ладно, ребята. Вот если бы 150 000 файлов в минуту, то, да, ещё можно было бы почитать.

      оперировать надо не кол-вом файлов, а объемом. В среднем получается 1.5 Тб. Нет задачи передать 1.5 Тб за минуту, задача передать все до последнего байта.

      Но главное: вообще нет никаких данных о скорости каналов передачи/приёма информации, частоте прихода файлов, скорости хранилища файлов, итд.

      Канал гигабитный. Нет определенной частоты прихода файлов, может 10 прилететь, а может 100 000 прилететь. Что имеется ввиду под скоростью хранилища файлов?

      Хотя бы какие-то выкладки должны быть, чтобы видеть, что ваше решение с Redis, Kafka, MinIO, Archive, Agent, Detector, Task-manager имеет преимущество над скриптом в 20 строк, кладущим входящие файлы в папку файловой системы и отдающим их, например, через curl.

      Среди готовых решений рассматривали Spring Data Flow, но от всего функционала подходил лишь транспортный уровень, так как у нас есть нетривиальная бизнес логика, то приняли решение разрабатывать своё решение на тех же компонентах что и Spring Data Flow.

      Скрипт из 20 строк это конечно мощно. Очень хотел бы глянуть )))


  1. Filex
    16.01.2023 13:13

    В статье https://habr.com/ru/company/veeam/blog/517392/ в комментариях описали проблемы minio при работе с большим количеством файлов. Вы как-то дополнительно тюнили MinIO?


    1. evseevvd
      16.01.2023 14:03
      +2

      Ну большое кол-во как то абстрактно, если это в пределах миллиарда то у нас столько не будет, min io как временно хранилище, т.е. есть ttl у объекта, второй кейс это архив, что тоже временное хранилище с последующим перемещением на ленточные накопители.


      1. Filex
        16.01.2023 14:37

        В комментариях к статье - при количестве более 10 млн. объектов начинается деградация.


        1. evseevvd
          16.01.2023 15:21
          +1

          у нас и такого не будет в моменте. TTL не большой. но спасибо учтем в будущем


  1. drblez
    16.01.2023 13:39
    +2

    И это все ради 18 мб/сек?


  1. stone_evil
    17.01.2023 07:45
    +2

    Использовать Oracle как персистентное хранилище правил и их истории - ну, такое себе (вроде как платное и тяжелое, есть куча бесплатных легких решений для этого).

    Использовать Kafka для транспорта файлов - ну, такое себе (вроде как есть ограничения по размеру и более простые паттерны).

    Ну и вообще непонятно, куда надо эти файлы транспортировать, зачем, какие требования? Почему просто не положить в S3 и не транспортировать линки? Речь вроде как идет о внутренней инфраструктуре.


    1. evseevvd
      17.01.2023 10:32
      -1

      Использовать Oracle как персистентное хранилище правил и их истории - ну, такое себе (вроде как платное и тяжелое, есть куча бесплатных легких решений для этого).

      требование заказчика

      Использовать Kafka для транспорта файлов - ну, такое себе (вроде как есть ограничения по размеру и более простые паттерны).

      кафка для передачи событий а не файлов

      Ну и вообще непонятно, куда надо эти файлы транспортировать, зачем, какие требования? Почему просто не положить в S3 и не транспортировать линки? Речь вроде как идет о внутренней инфраструктуре.

      переместить файл с SMB на FTP, выполнить кучу проверок до и после перемещения, положить в архив если надо и т.д. Защитится от того что кто то файл дописывает на источнике, восстановить работу если приемник отвалился. это если кратко о требованиях