> Есть ли у вас сильно нагруженные части системы (Go)
Уровень: middle · Роль: backend · Категория: Технические вопросы
Компании: Сбер
Стек: Go
> Пример ответа
Короткий ответ
Да, есть. Основная нагрузка приходится на сервис обработки событий - он принимает до 50k RPS, и на API-шлюз, который проксирует запросы к внутренним сервисам. Также выделяется consumer, который читает из Kafka и пишет в ClickHouse - там узкое место в батчинге и flush-интервалах. Мы это мониторим через Prometheus + Grafana, алерты стоят на latency и error rate.
Подробное объяснение
Нагруженные части системы можно разделить на три группы:
- Входящий трафик: API-шлюз на Go, обрабатывает все внешние запросы. Пиковая нагрузка - 30-50k RPS, latency p99 должен быть меньше 100ms. Здесь важна балансировка, таймауты и retry-политики, чтобы не ронять нижестоящие сервисы.
- Обработка событий: сервис-приёмник событий, пишет в Kafka. Ключевая проблема - партиционирование и порядок сообщений. При перекосе ключей один consumer может перегружаться, а другие простаивать.
- Запись в хранилище: consumer из Kafka в ClickHouse. Узкое место - батчинг: слишком маленький батч даёт много маленьких insert'ов, слишком большой - рост latency и памяти. Также важно управлять flush-интервалом и числом concurrent workers.
Плюс есть фоновые задачи: периодическая агрегация метрик и очистка старых данных. Они не критичны по RPS, но могут создавать всплески CPU и IO.
На практике
Мы решаем проблемы нагрузки через:
- Горизонтальное масштабирование: stateless сервисы легко реплицируются, для stateful (Kafka consumer) - увеличиваем число партиций и consumer'ов.
- Rate limiting на шлюзе, чтобы защитить бэкенд от всплесков.
- Circuit breaker для вызовов к внешним зависимостям - если сервис деградирует, мы быстро отдаём fallback, а не ждём таймаут.
- Профилирование: pprof и trace в Go помогают находить аллокации и блокировки. Например, однажды нашли проблему в JSON-маршалинге больших структур - заменили на ручную сериализацию, latency упал в 3 раза.
- Мониторинг: дашборды по RPS, latency, error rate, saturation (CPU, memory, goroutines). Алерты на аномалии, а не на пороги.
Пример кода
Пример обработки батча в consumer с настройкой размера и flush-интервала:
GOtype BatchProcessor struct {batchSize intflushTimeout time.Durationbatch []EventflushCh chan []Event}func (bp *BatchProcessor) Add(ev Event) {bp.batch = append(bp.batch, ev)if len(bp.batch) >= bp.batchSize {bp.flush()}}func (bp *BatchProcessor) flush() {if len(bp.batch) == 0 {return}bp.flushCh <- bp.batchbp.batch = make([]Event, 0, bp.batchSize)}func (bp *BatchProcessor) Run(ctx context.Context) {ticker := time.NewTicker(bp.flushTimeout)defer ticker.Stop()for {select {case <-ctx.Done():bp.flush()returncase <-ticker.C:bp.flush()}}}
Здесь важно, что flush по таймеру не блокирует добавление новых событий - канал буферизован, и writer-горутина обрабатывает батчи асинхронно.
Как отвечать на собеседовании
- Начни с конкретики: назови сервисы и цифры (RPS, latency, объём данных). Это сразу показывает, что ты работал с реальной нагрузкой.
- Покажи системное мышление: упомяни не только сам сервис, но и зависимости (Kafka, БД, внешние API).
- Расскажи про инструменты мониторинга и алертинга - это обязательная часть для middle.
- Если есть опыт оптимизации - приведи конкретный кейс: что было узким местом, как нашёл, что изменил, какой эффект.
- Не углубляйся в детали реализации, если не спрашивают - дай обзор, а детали раскроешь на уточняющих вопросах.
Что проверяет интервьюер
- Понимание архитектуры и умение выделять узкие места.
- Опыт работы с нагрузкой: знает ли кандидат реальные цифры и проблемы.
- Владение инструментами: мониторинг, профилирование, балансировка.
- Умение объяснять trade-off: например, батчинг vs latency, партиционирование vs порядок.
- Насколько кандидат системно мыслит: видит ли он всю цепочку от запроса до записи в БД.
Типичные ошибки
- Отвечать абстрактно: "да, есть нагрузка" без цифр и конкретики.
- Называть только один сервис, игнорируя связанные компоненты.
- Не упоминать мониторинг и алерты - это красный флаг для middle.
- Говорить "мы просто добавили реплик" - без объяснения, почему это помогло и какие были ограничения.
- Путать понятия: например, считать RPS и throughput одним и тем же.
- Забывать про деградацию и fallback-механизмы - интервьюер ожидает, что ты думаешь об отказах.
> Похожие задачи по backend
Где хранится индекс и как к нему обращаются
Задумываетесь ли вы об оптимизации приложений
Как контролировать уникальные указатели и умножать их ровно один раз в функции double в Go
В какой версии Go был исправлен баг с указателями в цикле
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью