Разберём архитектуру пайплайна аналитики для финтех-продукта: от захвата событий до генерации отчётов. Узнайте, как избежать типичных ошибок и построить масштабируемую систему.
Представьте: вы работаете в финтех-стартапе, где полевые агенты занимаются онбордингом клиентов, управлением инвестициями и транзакциями. Руководство решает перейти от фиксированной зарплаты к схеме «оклад + комиссия», зависящей от ежемесячной производительности. Первая мысль — написать SQL-запрос. Но он быстро ломается: 7+ таблиц, перезапуск при каждом вопросе об агенте, любое изменение системы оплаты требует переписывания запроса, а ad-hoc отчёты для руководства превращаются в аврал. Проблема не в SQL, а в том, что система хранит события, а не состояние — чтобы получить текущее состояние, приходится вручную воспроизводить все события каждый раз. Эта статья покажет, как спроектировать пайплайн аналитики, который решает эту проблему.
Прежде чем прыгать в архитектуру, чётко сформулируем требования.
Обратите внимание, чего нет в требованиях: низкая задержка чтения, строгая согласованность, агрегации за секунды. Это система аналитики с конечной согласованностью и пакетной обработкой. Это определяет все дальнейшие решения.
Прикинем объём: ~50 действий агента в день на агента, ~200 агентов → ~10 000 событий/день. Каждое событие ~2 КБ (обогащённый JSON с контекстом) → ~20 МБ/день в сыром виде. Месячные отчёты покрывают ~300 000 событий — управляемо для пакетной обработки Lambda. За 12 месяцев: ~7 ГБ сырых событий — архивация в S3 экономически эффективна. При таком масштабе распределённая стриминговая платформа не нужна. Kafka здесь присутствует, но по другой причине — вернёмся к этому.
Дизайн разделён на три слабо связанные части. Это свойство plug-and-play: каждая часть может отказать или быть заменена без влияния на другие.
Каждый фронтенд (веб, мобильное приложение, приложение агента) отправляет события о значимых действиях пользователя. Бэкенд получает события, обогащает их в зависимости от типа (добавляет ID агента, контекст клиента, временную метку, метаданные сессии) и записывает в существующую РСУБД.
Почему РСУБД на этом этапе? Потому что каждое событие:
Cron-задача запускается с заданным интервалом, читает необработанные события, копирует их в AWS S3 и помечает для удаления. Второй проход удаляет помеченные записи. Этот двухэтапный паттерн (пометка → удаление) намеренный: если запись в S3 упадёт в середине пакета, ничего не удалится. Вы получаете доставку at-least-once в S3, что приемлемо для аналитики.
Жизненный цикл данных: через 12 месяцев в S3 события перемещаются в локальное NAS (или холодное хранилище типа S3 Glacier). Это снижает затраты на активное хранение без потери аудиторского следа.
[Веб-приложение / Мобильное приложение / Приложение агента]
|
▼
[Бэкенд-сервис] → обогащает событие → [Таблица-стейджинг в РСУБД]
|
[Cron-задача]
|
[AWS S3 Bucket]
|
(через 12 месяцев) → [NAS / Холодное хранилище]
Ключевая инсайт для собеседования: Cron-подход намеренно прост. В высоконагруженной системе вы бы заменили его на CDC (Change Data Capture) с Debezium или аналогом, но при таком масштабе простота побеждает.
Как только данные попали в S3, генерация отчётов становится задачей трансформации данных. Python-скрипты и AWS Lambda читают из S3, применяют агрегации и записывают результаты (CSV, JSON) обратно в указанную директорию S3.
Lambda здесь хорошо подходит, потому что:
Сгенерированные отчёты хранятся в S3, и запрашивающему отправляется уведомление (email со ссылкой для скачивания). Отчёт никогда не отправляется напрямую — только ссылка. Это отделяет задержку генерации от доставки.
Это уровень эксплуатации — и его часто упускают в ответах на проектирование систем.
Контроллер — это небольшой Java-модуль, который:
API по запросу работает по принципу fire-and-forget. Клиент вызывает POST /reports/generate с параметрами, получает 202 Accepted немедленно. Запрос отправляется в Kafka-топик. Потребитель забирает его, обрабатывает отчёт, записывает в S3 и отправляет email со ссылкой.
Почему Kafka, а не простая очередь задач или прямой вызов Lambda?
[Клиент] → POST /reports/generate
|
[REST Контроллер] → 202 Accepted
|
[Kafka топик: report-requests]
|
[Потребитель отчётов]
|
[S3 Выход] → [Email уведомление]
Вот вопросы, которые интервьюер, скорее всего, задаст:
Почему не стримить события напрямую в S3 вместо промежуточного хранения в РСУБД? Можно использовать Kinesis Firehose или Kafka напрямую. Но при таком масштабе РСУБД-стейджинг остаётся в рамках существующей операционной экспертизы команды. Cron-подход легко мониторить, отлаживать и воспроизводить при сбоях. Стриминг добавляет операционные накладные расходы, которые не оправданы, пока объём не потребует.
Почему не использовать специализированную аналитическую БД (Redshift, BigQuery) вместо S3 + Lambda? Для ad-hoc SQL-запросов и дашбордов лучше подошло бы хранилище. Но требование — структурированные отчёты по расписанию, а не исследовательская аналитика. S3 + Lambda дешевле, не имеет затрат на простой и точно соответствует паттерну доступа.
Что произойдёт, если cron упадёт на середине пакета? Паттерн «пометка, затем удаление» обрабатывает это. Неудалённые записи будут подхвачены следующим запуском cron и перезаписаны в S3 (идемпотентно, если ключи заданы правильно). Доставка at-least-once приемлема для аналитики.
Что, если объём отчётов вырастет в 100 раз? Замените cron на CDC + Kafka Streams для почти реального времени. Переместите генерацию отчётов из Lambda в Spark или Flink на EMR для крупных агрегаций. Дизайн, ориентированный на S3, позволяет мигрировать без изменения модели данных.
Три вещи, которые стоит запомнить:
| Вопрос | Ответ |
|---|---|
| Почему стейджинг в РСУБД перед S3? | Однократная запись, структурированность, транзакционность — соответствует паттерну доступа; проще, чем стриминг при таком масштабе |
| Почему Kafka для отчётов по запросу? | Долговечная, воспроизводимая, обрабатывает обратное давление — API fire-and-forget требует гарантии асинхронной обработки |
| Почему Lambda для генерации отчётов? | Пакетные задачи без состояния, оплата за использование, нет затрат на простой — идеально подходит для рабочей нагрузки |
| Как обрабатывать сбой cron? | Пометка на удаление перед удалением — необработанные записи подхватываются следующим запуском |
| Как масштабировать систему? | CDC + Kafka Streams заменяет cron; Spark/Flink заменяет Lambda при высоком объёме |
| Каков жизненный цикл данных? | Горячие (РСУБД-стейджинг) → Тёплые (S3, 12 месяцев) → Холодные (NAS/Glacier) |
Лучшие ответы на проектирование систем не начинаются с «давайте использовать Kafka и микросервисы». Они начинаются с проблемы, рассуждают об ограничениях и приходят к самой простой архитектуре, удовлетворяющей требованиям — с чётким указанием, что изменить, если эти ограничения изменятся. Этот пайплайн намеренно прост. И в этом суть.
Практический вывод: Прямо сейчас возьмите реальную задачу аналитики из вашего проекта и нарисуйте трёхчастную архитектуру, описанную выше. Определите, где у вас сейчас узкие места, и подумайте, как разделение на захват, обработку и контроллер может их решить.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →