Как организовать взаимодействие между сервисом коротких ссылок и сервисом аналитики
Что проверяют
Умеете ли вы отделить горячий путь от второстепенного: редирект должен работать быстро и даже тогда, когда аналитика лежит. Следом обычно спрашивают про гарантии доставки событий и про поведение при всплеске трафика.
Как отвечать
Начните с потоков данных. Основная нагрузка это редирект GET /{code}, и на каждый переход аналитике нужно событие о клике. Синхронный вызов по HTTP или gRPC на каждый редирект отвергайте сразу: он добавляет задержку и связывает доступность двух сервисов.
Каркас решения:
- событие клика:
event_id, код ссылки, время, реферер, user agent, страна или хеш IP. Схему описывают в Protobuf и версионируют; - брокер: Kafka с ключом партиции по коду ссылки, если нужны хранение и повторное чтение, либо NATS JetStream как более лёгкий вариант. Аналитика читает своей consumer group и масштабируется независимо;
- отправка в Go: хендлер не ждёт брокер, а кладёт событие в буферизованный канал через
selectс веткойdefault, чтобы при переполнении событие отбросилось, а не заблокировало редирект. Отдельная горутина собирает пачки по размеру или по таймеру, а при остановке поcontextдописывает буфер; - гарантии: доставка «хотя бы один раз» даёт дубли, поэтому консьюмер дедуплицирует по
event_id. Для кликов обычно допустима небольшая потеря, а события о создании ссылок стоит писать через transactional outbox; - хранилище аналитики: колоночная база вроде ClickHouse с агрегатами по времени, у сервиса ссылок своё хранилище и кеш в Redis;
- чтение статистики: дашборд ходит в API аналитики напрямую, сервис ссылок в этой цепочке не участвует.
Где спотыкаются
Отдают редирект со статусом 301. Браузер кеширует постоянный редирект, повторные переходы до сервера не доходят, и клики пропадают из статистики. Для учёта нужен 302 или 307.
Пишут клик в базу прямо в хендлере редиректа. При всплеске трафика запись становится узким местом, и тормозит самая важная операция.
Запускают go sendEvent(...) на каждый запрос без ограничений. При недоступном брокере горутины копятся тысячами и съедают память, нужен ограниченный буфер и фиксированный пул воркеров.