> Какое взаимодействие между сервисами предпочтительнее: синхронное или асинхронное (Go)

Уровень: senior · Роль: backend · Категория: Технические вопросы

Компании: InDrive, sferaplatform.ru

Стек: Go

> Пример ответа

Короткий ответ

Асинхронное взаимодействие предпочтительнее для систем с высокой нагрузкой, слабой связанностью и требованиями к отказоустойчивости. Синхронное - когда критичен немедленный ответ, простота отладки и консистентность данных. Универсального ответа нет: выбор зависит от бизнес-требований, SLA и топологии сервисов. В реальных системах обычно используют гибридный подход: синхронные вызовы для read-путей и асинхронные - для write-операций, не требующих мгновенного подтверждения.

Подробное объяснение

Синхронное взаимодействие (HTTP/gRPC) даёт предсказуемую семантику: клиент получает ответ и знает результат операции. Это упрощает обработку ошибок, транзакционность и отладку. Минусы: блокировка ресурсов, каскадные таймауты, деградация при пиковых нагрузках, жёсткая связанность времени жизни запроса.

Асинхронное (message queue, event bus, Kafka, NATS) развязывает отправителя и получателя: producer не ждёт обработки, система переживает всплески за счёт буферизации, легко добавлять новых потребителей. Минусы: сложнее гарантировать доставку, идемпотентность, порядок событий; появляется eventual consistency; сложнее отладка распределённых сценариев.

Ключевые критерии выбора:

  • latency budget: если клиенту нужен ответ <100ms - синхронно
  • критичность данных: потеря события недопустима - нужен надёжный брокер с retry
  • масштабирование: асинхронность позволяет независимо масштабировать consumer'ов
  • сложность операций: длительные задачи (рендеринг, email-рассылка) - только асинхронно
  • согласованность: если нужна строгая консистентность - синхронно или сага с компенсацией

На практике

Для Go-сервисов типичный паттерн:

  • gRPC для внутренних синхронных вызовов с mTLS и таймаутами
  • Kafka/NATS для событий домена, аудита, интеграций
  • Redis Streams для простых очередей задач
  • outbox pattern для гарантии публикации событий вместе с транзакцией БД

Важно проектировать API с учётом обоих стилей: например, POST /orders возвращает 202 Accepted и ссылку на статус, а не 200 с телом заказа. Для синхронных вызовов обязательны: context with timeout, circuit breaker, retry с exponential backoff, bulkhead isolation.

Пример кода

GO
// Асинхронная обработка через Kafka в Go
func (s *Service) CreateOrder(ctx context.Context, req *OrderRequest) (*OrderResponse, error) {
// валидация и сохранение в БД
order := s.repo.Save(ctx, req)
// публикация события через outbox
err := s.producer.Publish(ctx, "order.created", order)
if err != nil {
return nil, fmt.Errorf("publish event: %w", err)
}
// возвращаем 202 Accepted
return &OrderResponse{Status: "accepted", OrderID: order.ID}, nil
}
// Consumer с идемпотентностью
func (c *Consumer) HandleOrderCreated(ctx context.Context, event OrderCreated) error {
// проверяем, не обрабатывали ли уже
if c.repo.Exists(ctx, event.OrderID) {
return nil
}
// бизнес-логика
if err := c.processOrder(ctx, event); err != nil {
return fmt.Errorf("process order: %w", err) // Kafka retry
}
return c.repo.MarkProcessed(ctx, event.OrderID)
}

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

Начните с того, что нет универсального ответа - это trade-off. Затем перечислите критерии выбора: latency, consistency, throughput, coupling. Приведите пример из практики: почему выбрали очередь для одного сценария и gRPC для другого. Упомяните паттерны: outbox, saga, circuit breaker. Покажите понимание последствий: eventual consistency, идемпотентность, dead letter queue. Если спросят про Go - расскажите про goroutine-модель для конкурентной обработки событий и особенности работы с Kafka consumer groups.

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

  • Понимание trade-off, а не заученных определений
  • Умение связывать архитектурный выбор с бизнес-требованиями
  • Знание конкретных инструментов и паттернов (outbox, saga)
  • Осознание сложностей асинхронности: дубликаты, порядок, отказ брокера
  • Практический опыт: как дебажить распределённые системы, мониторинг очередей

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

  • Категоричное утверждение "асинхронно всегда лучше" - сразу видно отсутствие опыта
  • Игнорирование проблемы идемпотентности при асинхронной обработке
  • Отсутствие упоминания таймаутов и retry для синхронных вызовов
  • Путаница между асинхронным I/O (goroutine) и асинхронной архитектурой сервисов
  • Непонимание, что синхронный вызов тоже может быть неблокирующим (gRPC async client)
  • Забывают про мониторинг: в асинхронной системе нужны метрики глубины очереди, lag consumer'ов

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

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