stanislav_dubich@dev:~$ cat url-shortener/README.md

URL Shortener

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

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

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

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

Редирект должен быть мгновенным, но при этом нужно записать ~20 параметров аналитики. Синхронная запись в БД убивает время отклика.

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

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Nginx     │────▶│ link-server │────▶│  Memcached  │
│             │     │ (редиректы) │     │ (3h TTL)    │
└─────────────┘     └──────┬──────┘     └─────────────┘
                           │ async
              ┌────────────┼────────────┐
              ▼            ▼            ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ RabbitMQ │ │  Redis   │ │ backend  │
        │  (hits)  │ │(sessions)│ │  (API)   │
        └────┬─────┘ └──────────┘ └──────────┘
             │ Table Engine
        ┌────▼─────┐
        │ClickHouse│
        │(analytics)│
        └──────────┘
                

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

Зачем два кэша: разные типы данных — разные требования.

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

Проблема: MongoDB не справлялась с аналитическими запросами по миллионам записей.

Решение: RabbitMQ Table Engine для потоковой вставки без промежуточных преобразований. Данные доступны для отчётов с задержкой < 2 сек. ReplacingMergeTree для дедупликации повторных событий.

25+ измерений на каждый переход. Партиционирование по месяцам. Мгновенные срезы по любой комбинации.

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

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

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

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

Стек

Backend

Java 11 Spring Boot Spring Data JPA Spring Security gRPC Liquibase

Data

PostgreSQL ClickHouse Redis Memcached RabbitMQ

Infra

Docker Nginx GitLab CI/CD MaxMind GeoIP2

Моя роль

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