stanislav_dubich@dev:~$ cat ss7-routing-platform/README.md

SS7 Routing Platform

200+ стран/операторов. ~1K SMS/сек × 70 операций на каждую = 70K RPS внутри системы. 99.9% uptime. 4 года в production.

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

SMS-агрегатор работает с сотнями операторов по всему миру. Прямое подключение к SS7-сети дешевле, чем через SMPP-шлюзы, но требует сложной маршрутизации: выбрать оптимальный путь по цене, качеству и доступности.

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

SS7-протокол не позволяет отправить две SMS на один номер одновременно — вторая будет отброшена. При этом система должна держать тысячи параллельных отправок на разные номера.

Решение: декомпозиция по MSISDN. Каждый номер — своя мини-очередь в Redis. Kafka распределяет нагрузку между потребителями. Один номер обрабатывается строго последовательно, разные номера — параллельно.

                        ┌─────────────────┐
                        │   API Gateway   │
                        └────────┬────────┘
                                 │
┌────────────────────────────────▼────────────────────────────────┐
│                           Kafka                                 │
│     Изоляция: отдельные топики для SRI/FWSM/логов/событий.      │
│         Независимое масштабирование каждого этапа.              │
└──────┬──────────────────────────────────────────────┬───────────┘
       │                                              │
┌──────▼──────┐  gRPC streaming   ┌──────────────────▼───────────┐
│  sms-flow   │◀─────────────────▶│          smsc-api            │
│   (ядро)    │  bidirectional    │  (адаптер к оборудованию)    │
└──────┬──────┘                   └──────────────────────────────┘
       │                                              │
┌──────▼──────┐                   ┌──────────────────▼───────────┐
│    Redis    │                   │     SS7 Equipment            │
└─────────────┘                   │  (проприетарный протокол)    │
                                  └──────────────────────────────┘
                

Почему реактивный стек

Проблема: SS7-операции (SRI, FWSM) занимают 2-16 секунд — это время ответа сети. Блокирующий ввод-вывод: 1000 параллельных запросов = 1000 потоков, каждый висит и ждёт. JVM не любит 10K+ потоков.

Решение: WebFlux + Reactor Kafka + Reactive Redis + R2DBC. Неблокирующий ввод-вывод: поток отправляет запрос и переключается на другой. Обратное давление: если нижестоящий слой не справляется — автоматическое замедление вышестоящего.

Результат: 1K SMS/сек × ~70 внутренних операций = 70K RPS. Стабильная работа без роста потоков.

Почему gRPC streaming

Зачем smsc-api отдельно: SS7-оборудование работает по проприетарному бинарному протоколу и требует специфичного окружения. smsc-api изолирует драйвер оборудования от бизнес-логики — можно обновлять/рестартить независимо.

Проблема: smsc-api отправляет запрос в SS7-сеть и ждёт ответа 2-16 секунд. HTTP запрос-ответ: либо таймаут, либо держать соединение открытым и блокировать поток.

Решение: двунаправленный стриминг. Запрос уходит, соединение живёт, ответ приходит асинхронно. sms-flow может отправить 1000 запросов и получать ответы в произвольном порядке по мере готовности.

Стратегия TTL (Redis)

Разные данные — разное время жизни. Это не «кэш ради кэша», а требования домена:

ClickHouse: аналитика

Аналитика доставки SMS. Миллиарды записей, мгновенный поиск по любому срезу: оператор, маршрут, время, статус.

Маршрутизация: 118 таблиц — зачем?

Выбор маршрута — это комбинация факторов: страна + оператор + отправитель + время суток + текущая загрузка + история ошибок + цена. Каждый фактор — отдельные таблицы со связями.

Важно: 118 таблиц — это схема для гибкой настройки менеджерами через админку. В рантайме JOIN-ов нет: конфигурация агрегируется в Redis-кэш с TTL, маршрутизация работает по данным в памяти.

Стек

Backend

Java 17 Spring Boot Spring WebFlux Project Reactor R2DBC Reactor Kafka gRPC Lombok

Data

PostgreSQL ClickHouse Redis Apache Kafka Liquibase

Frontend

Vue 2 Vuex Vue Router Bootstrap Vue Chart.js Axios

Infra

Docker Docker Compose Prometheus Grafana SonarQube GitLab CI/CD

Моя роль

Архитектура с нуля, выбор стека, реализация 4 микросервисов, оптимизация под нагрузку. Принимал решения по всем техническим вопросам: от структуры БД до стратегии деплоя.