Вполне логично предположить, что сократитель ссылок — довольно простой сервис как с точки зрения пользователя, так и под капотом. Но что, если, взяв за основу такую простую задачу, построить целую распределенную систему?

Мой шортенер начинался как простая практика с Go и gRPC после всех ОГЭ :-), где должно было быть 3 простеньких сервиса: inline тг бот, API gateway и ядро. Но с каждым днем идей все больше, энтузиазм растёт, я стал делать упор на высокие нагрузки, и постепенно мини-практика начала становиться боевой event-driven машиной. В этой статье я хотел бы подметить интересную мысль: даже самая простая вещь может быть реализована сложно.

Архитектура всего проекта
Архитектура всего проекта

Метрики

Чтобы наблюдать за количеством сокращений и переходов, нам нужны метрики. Конечно, мы можем подключить их в "ядре", и запариваться не придется, но мне хотелось прочувствовать микросервисы. И я выделил отдельный сервис - сервис статистик. Окей, Prometheus есть, сервис есть, но теперь нам надо как-то подружить его с ядром. Идеальный выбор - Kafka. Ядро асинхронно публикует события, а сервис статистик забирает их, когда хочет. Такой подход обеспечивает слабую связность: ядро не знает о статистике, а статистика не знает о ядре.

Кэширование

Мы же говорим о высоких нагрузках? Нам необходим кэш. Я выбрал Valkey (форк Redis) для этих целей.

Как кэшировать?

Так как у нас теперь есть отдельный сервис для всех аналитических данных, давайте подключим к нему ClickHouse и будем писать все события в него.

Отлично! Теперь мы можем периодически собирать топ популярных ссылок по переходам, исходя из тех самых событий.

Как мы этот топ доставим до кэша? Все просто, снова воспользуемся кафкой. Ядро заберет его и запишет к себе в Valkey.

Проблема масштабирования сервиса статистик

Среди этой схемы есть маааленькая проблемка: если у нас несколько инстансов статистик, каждый из них отправит топ в определенный момент. Мы явно не хотим получать кучу одинаковых сообщений в кафку. Это просто засоряет канал.

Как чинить?

Выход есть — распределенный лок!

Подключим к сервису статистик свой Valkey, в который он будет писать одно значение с ттл при сборе топа. Таким образом, первый успевший захватить лок сможет собрать и отправить топ, а остальные получат отказ, потому что значение в Valkey уже существует.

Трассировка

У нас уже 4 сервиса, и нам надо как-то следить за запросом по всем четырём. Смотреть логи каждого слишком нудно и долго. На помощь приходит трассировка с OpenTelemetry. Эта вещь позволяет "трассировать" один запрос через все сервисы, не теряя контекст. Даже в кафку мы можем пропихнуть trace id в заголовках сообщения и тогда не потеряем трейс при прохождении через брокер. Но сам по себе OpenTelemetry не поставляет никакого UI, он лишь является бэкендом. В качестве веб-морды можно использовать Jaeger. Он предоставляет удобный интерфейс для просмотра трейсов.

Jaeger UI
Jaeger UI

И я уже вижу вопрос «зачем весь этот оверинжиниринг для сокращения ссылок?»:‑). Моя тактика заключалась в том, чтобы не заостряться на бизнес‑логике ради изучения инфраструктуры. Это позволило мне эффективно потрогать множество продакшн технологий.

Вся система от начала и до конца написана на Go. Это был невероятно увлекательный путь, но вполне возможно, что он еще не прекращается! Реализацию можно глянуть на GitHub.

Буду рад вашим комментариям!

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


  1. SiGGthror
    07.08.2025 11:31

    Это не микросервисы, это распределенный монолит. Если shortener нужны данные по статистике для работы, то они и должны хранится/обрабатываться в нем же.
    Но вообще вся затея с топом кеша не имеет смысла и скорее всего вредит. Например, был супер популярный ресурс, который за 2 дня насобирал миллионы просмотров, но потом стал не актуален. Зачем нам хранить ссылку на этот ресурс постоянно?


    1. misshanya7 Автор
      07.08.2025 11:31

      Вы правы, с академической точки зрения это больше похоже на распределенный монолит. Моя идея заключалась в том, чтобы попробовать потыкать и собрать всю эту связку, поэтому насчет целесообразности моей системы в продакшене действительно есть вопросы.

      Про популярный ресурс. Мы же не будем всегда хранить в кэше эту ссылку. Топ составляется не по абсолютной популярности, а по популярности за последний час (время конфигурируется), и сами записи в кэше имеют ttl.


      1. SiGGthror
        07.08.2025 11:31

        LFU на уровне valkey не приведут к тому же самому?


        1. misshanya7 Автор
          07.08.2025 11:31

          Да, можно подумать над этим. Но гибкости чуть меньше будет


          1. SiGGthror
            07.08.2025 11:31

            А в чем нужна гибкость в вопросе хранения ссылок в кеше?


            1. misshanya7 Автор
              07.08.2025 11:31

              Например я бы мог в будущем прокачать стратегию кэширования. Условно какую-нибудь модельку пихнуть на анализ. Но да, щас рано о таком думать будто бы)


  1. Dhwtj
    07.08.2025 11:31

    Моя тактика заключалась в том, чтобы не заостряться на бизнес‑логике ради изучения инфраструктуры. 

    наоборот, интереснее как это монетизировать

    Бесплатный пользователь:
    → кликает по ссылке
    → видит 3-секундную рекламу, переходит по ссылке

    → или видит баннер внедренный на страницу

    Премиум-пользователь:
    → кликает
    → мгновенный редирект
    → кастомная ссылка
    → полная статистика

    Компания:
    → покупает домен go.ихсайт.com
    → интегрирует с API
    → платит $50/мес

    Вы:
    → собираете агрегированные данные
    → продаёте отчёт "Тренды в Telegram-трафике"


    1. misshanya7 Автор
      07.08.2025 11:31

      звучит интересно)


    1. SiGGthror
      07.08.2025 11:31

      Бесплатный пользователь:
      → кликает по ссылке
      → видит 3-секундную рекламу, переходит по ссылке

      Сами бы стали таким пользоваться?))


      1. Dhwtj
        07.08.2025 11:31

        был сервис хранения файлов, он работал по этой модели монетизации


  1. MyraJKee
    07.08.2025 11:31

    Чем бы дитя не решилось. Случайно не с курсов яндекс.практикум?) Один из учебных проектов - шортенер. Но думаю там менторы не оценили бы на столько безумный оверинжиниринг.


    1. misshanya7 Автор
      07.08.2025 11:31

      Не, я там никогда не был :)


  1. mrhearthstone
    07.08.2025 11:31

    Отличная архитектура и цели - посмотреть как применяются технологии, я вижу Вы добились. Так держать!


    1. misshanya7 Автор
      07.08.2025 11:31

      Спасибо!