Все проекты

URL Shortener

Рефакторинг NodeJS → Java. Разделение путей чтения и записи. Редирект < 20ms, аналитика без ожидания.

Редирект < 20ms25+ измерений аналитикиЗадержка аналитики < 2 сек

Бизнес-задача

Сервис сокращения ссылок с детальной аналитикой переходов. Исходная система на NodeJS + MongoDB не справлялась: медленная аналитика, негибкие лимиты, сложности с масштабированием.

Ключевая задача

Редирект должен быть мгновенным, но при этом нужно записать ~20 параметров аналитики. Синхронная запись в БД убивает время отклика. Решение: разделение путей чтения и записи. Редирект из in-memory кэша за < 20ms. Событие аналитики уходит в RabbitMQ без ожидания ответа — пользователь не ждёт записи.

Архитектура

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Nginx     │────▶│ link-server │────▶│  Memcached  │
└─────────────┘     └──────┬──────┘     └─────────────┘
                           │ async
              ┌────────────┼────────────┐
              ▼            ▼            ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ RabbitMQ │ │  Redis   │ │ backend  │
        │  (hits)  │ │(sessions)│ │  (API)   │
        └────┬─────┘ └──────────┘ └──────────┘
             │
        ┌────┴─────┐
        │ClickHouse│
        └──────────┘

Специализация кэшей

Зачем два кэша: разные типы данных — разные требования.
  • Memcached — горячие ссылки. Без состояния, многопоточное чтение. При массовом чтении избегаем узкого места однопоточности
  • Redis — сессии, JWT-токены, счётчики ограничения частоты. С состоянием, персистентность между рестартами

ClickHouse: потоковая аналитика

MongoDB не справлялась с аналитическими запросами по миллионам записей. RabbitMQ Table Engine для потоковой вставки без промежуточных преобразований. Данные доступны для отчётов с задержкой < 2 сек. ReplacingMergeTree для дедупликации повторных событий. 25+ измерений на каждый переход. Партиционирование по месяцам. Мгновенные срезы по любой комбинации.

Защита от ботов

Анализ трафика на лету: GeoIP + разбор UserAgent. Блокировка бот-сетей до попадания в аналитику. Стоп-лист с комплексной логикой: IP-диапазоны (CIDR), регулярные выражения по URL, комбинации AND/OR.

Почему микросервисы

Резолвер ссылок (редиректы) и приём аналитики имеют разные требования к масштабированию: ограничение по вводу-выводу vs ограничение по процессору. Независимое масштабирование каждого слоя.

Технологии

Backend

Java 11Spring BootSpring Data JPASpring SecuritygRPCLiquibase

Data

PostgreSQLClickHouseRedisMemcachedRabbitMQ

Infra

DockerNginxGitLab CI/CDMaxMind GeoIP2

Моя роль

Полный рефакторинг: от legacy NodeJS/MongoDB к микросервисной Java-системе. Архитектура, выбор стека, реализация ключевых сервисов (резолвер ссылок, API Gateway) и вспомогательных воркеров.

  • Спроектировал асинхронный конвейер RabbitMQ → ClickHouse
  • Реализовал гибридную схему кэширования (Memcached для чтения + Redis для данных с состоянием)
  • Внедрил gRPC для межсервисного взаимодействия
  • Настроил OAuth2 (Google, Яндекс) + JWT авторизацию