Вполне логично предположить, что сократитель ссылок — довольно простой сервис как с точки зрения пользователя, так и под капотом. Но что, если, взяв за основу такую простую задачу, построить целую распределенную систему?
Мой шортенер начинался как простая практика с Go и gRPC после всех ОГЭ :-), где должно было быть 3 простеньких сервиса: inline тг бот, API gateway и ядро. Но с каждым днем идей все больше, энтузиазм растёт, я стал делать упор на высокие нагрузки, и постепенно мини-практика начала становиться боевой event-driven машиной. В этой статье я хотел бы подметить интересную мысль: даже самая простая вещь может быть реализована сложно.
Метрики
Чтобы наблюдать за количеством сокращений и переходов, нам нужны метрики. Конечно, мы можем подключить их в «ядре», и запариваться не придется, но мне хотелось прочувствовать микросервисы. И я выделил отдельный сервис — сервис статистик. Окей, Prometheus есть, сервис есть, но теперь нам надо как-то подружить его с ядром. Идеальный выбор — Kafka. Ядро асинхронно публикует события, а сервис статистик забирает их, когда хочет. Такой подход обеспечивает слабую связность: ядро не знает о статистике, а статистика не знает о ядре.
Кэширование
Мы же говорим о высоких нагрузках? Нам необходим кэш. Я выбрал Valkey (форк Redis) для этих целей.
Как кэшировать?
Так как у нас теперь есть отдельный сервис для всех аналитических данных, давайте подключим к нему ClickHouse и будем писать все события в него.
Отлично! Теперь мы можем периодически собирать топ популярных ссылок по переходам, исходя из тех самых событий.
Как мы этот топ доставим до кэша? Все просто, снова воспользуемся кафкой. Ядро заберет его и запишет к себе в Valkey.
Проблема масштабирования сервиса статистик
Среди этой схемы есть маааленькая проблемка: если у нас несколько инстансов статистик, каждый из них отправит топ в определенный момент. Мы явно не хотим получать кучу одинаковых сообщений в кафку. Это просто засоряет канал.
Как чинить?
Выход есть — распределенный лок!
Подключим к сервису статистик свой Valkey, в который он будет писать одно значение с ттл при сборе топа. Таким образом, первый успевший захватить лок сможет собрать и отправить топ, а остальные получат отказ, потому что значение в Valkey уже существует.
Трассировка
У нас уже 4 сервиса, и нам надо как-то следить за запросом по всем четырём. Смотреть логи каждого слишком нудно и долго. На помощь приходит трассировка с OpenTelemetry. Эта вещь позволяет «трассировать» один запрос через все сервисы, не теряя контекст. Даже в кафку мы можем пропихнуть trace id в заголовках сообщения и тогда не потеряем трейс при прохождении через брокер. Но сам по себе OpenTelemetry не поставляет никакого UI, он лишь является бэкендом. В качестве веб-морды можно использовать Jaeger. Он предоставляет удобный интерфейс для просмотра трейсов.
И я уже вижу вопрос «зачем весь этот оверинжиниринг для сокращения ссылок?»:‑). Моя тактика заключалась в том, чтобы не заостряться на бизнес‑логике ради изучения инфраструктуры. Это позволило мне эффективно потрогать множество продакшн технологий.
Вся система от начала и до конца написана на Go. Это был невероятно увлекательный путь, но вполне возможно, что он еще не прекращается! Реализацию можно глянуть на GitHub.
Буду рад вашим комментариям!
ссылка на оригинал статьи https://habr.com/ru/articles/934896/
Добавить комментарий