> Есть ли у вас сильно нагруженные части системы (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-интервала:

GO
type BatchProcessor struct {
batchSize int
flushTimeout time.Duration
batch []Event
flushCh 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.batch
bp.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()
return
case <-ticker.C:
bp.flush()
}
}
}

Здесь важно, что flush по таймеру не блокирует добавление новых событий - канал буферизован, и writer-горутина обрабатывает батчи асинхронно.

Как отвечать на собеседовании

  • Начни с конкретики: назови сервисы и цифры (RPS, latency, объём данных). Это сразу показывает, что ты работал с реальной нагрузкой.
  • Покажи системное мышление: упомяни не только сам сервис, но и зависимости (Kafka, БД, внешние API).
  • Расскажи про инструменты мониторинга и алертинга - это обязательная часть для middle.
  • Если есть опыт оптимизации - приведи конкретный кейс: что было узким местом, как нашёл, что изменил, какой эффект.
  • Не углубляйся в детали реализации, если не спрашивают - дай обзор, а детали раскроешь на уточняющих вопросах.

Что проверяет интервьюер

  • Понимание архитектуры и умение выделять узкие места.
  • Опыт работы с нагрузкой: знает ли кандидат реальные цифры и проблемы.
  • Владение инструментами: мониторинг, профилирование, балансировка.
  • Умение объяснять trade-off: например, батчинг vs latency, партиционирование vs порядок.
  • Насколько кандидат системно мыслит: видит ли он всю цепочку от запроса до записи в БД.

Типичные ошибки

  • Отвечать абстрактно: "да, есть нагрузка" без цифр и конкретики.
  • Называть только один сервис, игнорируя связанные компоненты.
  • Не упоминать мониторинг и алерты - это красный флаг для middle.
  • Говорить "мы просто добавили реплик" - без объяснения, почему это помогло и какие были ограничения.
  • Путать понятия: например, считать RPS и throughput одним и тем же.
  • Забывать про деградацию и fallback-механизмы - интервьюер ожидает, что ты думаешь об отказах.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью