Как организовать сервис для приема, хранения и быстрого возврата данных из Kafka с высокой производительностью
Что проверяют
Для тестировщика это обычно задача из автоматизации: автотестам нужно быстро убеждаться, что сервис отправил в Kafka нужное сообщение, а читать топик из каждого теста долго и нестабильно. Интервьюер смотрит, понимаете ли вы устройство consumer group и партиций. Следом спросят, как тест найдёт своё сообщение среди тысяч чужих.
Как отвечать
Опишите вспомогательный сервис, который постоянно читает топики и отдаёт сообщения тестам по запросу:
- постоянный consumer: один сервис со своей группой, а не новая группа на каждый тест. Вход новой группы вызывает ребалансировку, а для пустой группы брокер ещё и выжидает
group.initial.rebalance.delay.ms, по умолчанию 3 секунды; - параллелизм: внутри группы одну партицию читает один consumer, поэтому экземпляров больше, чем партиций, ставить бессмысленно. Пропускную способность добавляют пачки:
max.poll.records(по умолчанию 500),fetch.min.bytes,fetch.max.wait.ms; - хранение: сообщения складываются в индекс по ключу или по заголовку с trace id. Для короткого окна хватит памяти или Redis с TTL, для поиска по полям подойдёт ClickHouse или Elasticsearch, но всегда с лимитом объёма;
- API для тестов:
GET /messages?topic=...&key=...с ожиданием на стороне сервиса до таймаута. ВместоThread.sleepтест ждёт сообщения через Awaitility; - изоляция тестов: каждый тест генерирует уникальный id, передаёт его в систему и ищет по нему. Тогда параллельный прогон не путает сообщения;
- метрики: consumer lag группы и время от записи в топик до появления в индексе. Растущий лаг объясняет нестабильные тесты раньше, чем логи.
Про порядок: Kafka гарантирует его только внутри партиции, поэтому проверять порядок имеет смысл лишь для сообщений с одним ключом.
Где спотыкаются
Создают consumer в каждом тесте с auto.offset.reset=earliest и перечитывают весь топик. Прогон растягивается на минуты.
Проверяют «сообщение не пришло» коротким ожиданием. Отсутствие события подтверждается только временем, и этот таймаут нужно обосновать, а не брать наугад.
Забывают, что по умолчанию auto.offset.reset=latest: сервис, запущенный после отправки, сообщение просто не увидит.