> Какие паттерны микросервисов использовались, например саги, apigateway (Go)

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

Компании: BetBoom

Стек: Go

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

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

Да, в микросервисной архитектуре я использовал саги для распределённых транзакций и API Gateway как единую точку входа. Саги реализовывал через choreography на основе событий и orchestration с помощью отдельного координатора. API Gateway применял для маршрутизации, агрегации ответов, аутентификации и rate limiting. В Go это хорошо ложится на паттерны из стандартной библиотеки и популярных фреймворков.

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

Саги - это способ управления распределёнными транзакциями, когда каждая операция имеет компенсирующее действие. Два подхода:

  • Choreography: сервисы обмениваются событиями, каждый сам решает, что делать дальше. Минус - сложно отслеживать поток, легко получить циклические зависимости.
  • Orchestration: центральный координатор вызывает сервисы по очереди и запускает компенсации при ошибке. Проще дебажить, но добавляет единую точку отказа.

API Gateway решает задачи:

  • маршрутизация запросов к нужным сервисам;
  • агрегация данных из нескольких сервисов для одного клиентского запроса;
  • аутентификация и авторизация на входе;
  • rate limiting, circuit breaker, логирование;
  • трансформация протоколов (например, gRPC наружу как REST).

В Go для API Gateway часто используют net/http, chi, gin, или готовые решения типа Kong, Traefik, Envoy. Для саг - паттерн outbox для надёжной публикации событий и отдельные пакеты для работы с Kafka или NATS.

На практике

В одном проекте я делал заказ: сервис заказов, сервис оплаты, сервис доставки. Использовал orchestration-сагу: координатор в сервисе заказов вызывал оплату, затем доставку. При сбое оплаты - компенсация в виде отмены заказа. При сбое доставки - возврат денег через компенсацию в сервисе оплаты.

API Gateway был отдельным Go-сервисом на chi. Он проверял JWT, проксировал запросы в нужные сервисы, агрегировал данные для страницы заказа (заказ + статус оплаты + статус доставки). Rate limiting делал через golang.org/x/time/rate.

Для надёжности событий использовал outbox-паттерн: запись в БД и публикация события в одном локальном транзакционном блоке, затем отдельный воркер читал outbox-таблицу и отправлял в Kafka.

Пример кода

Пример orchestration-саги на Go:

GO
type SagaCoordinator struct {
paymentClient *PaymentClient
deliveryClient *DeliveryClient
}
func (s *SagaCoordinator) PlaceOrder(ctx context.Context, order Order) error {
// шаг 1: оплата
if err := s.paymentClient.Charge(ctx, order); err != nil {
return fmt.Errorf("charge failed: %w", err)
}
// шаг 2: доставка
if err := s.deliveryClient.Schedule(ctx, order); err != nil {
// компенсация: возврат денег
if compErr := s.paymentClient.Refund(ctx, order); compErr != nil {
return fmt.Errorf("delivery failed and refund failed: %v, %w", compErr, err)
}
return fmt.Errorf("delivery failed: %w", err)
}
return nil
}

Пример API Gateway с агрегацией:

GO
func (g *Gateway) GetOrderDetails(w http.ResponseWriter, r *http.Request) {
orderID := chi.URLParam(r, "id")
// параллельные вызовы к сервисам
var order Order
var payment Payment
var delivery Delivery
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
order, _ = g.orderClient.Get(r.Context(), orderID)
}()
go func() {
defer wg.Done()
payment, _ = g.paymentClient.GetByOrder(r.Context(), orderID)
}()
go func() {
defer wg.Done()
delivery, _ = g.deliveryClient.GetByOrder(r.Context(), orderID)
}()
wg.Wait()
// агрегированный ответ
json.NewEncoder(w).Encode(map[string]interface{}{
"order": order,
"payment": payment,
"delivery": delivery,
})
}

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

Начни с того, что оба паттерна - базовые для микросервисов. Затем кратко опиши, где именно применял. Упомяни trade-off: саги дают eventual consistency вместо ACID, API Gateway добавляет слой, который может стать узким местом. Покажи, что понимаешь, когда сага не нужна (например, можно обойтись без распределённой транзакции). Если спросят про альтернативы - скажи про transactional outbox, event sourcing, BFF для gateway. Говори конкретно: называй инструменты, которые использовал в Go.

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

Интервьюер хочет увидеть:

  • понимание проблем распределённых систем: согласованность, сбои, идемпотентность;
  • умение выбирать между choreography и orchestration;
  • знание, как API Gateway вписывается в архитектуру и какие задачи решает;
  • практический опыт: не просто названия, а реальные кейсы и ошибки;
  • способность объяснить компенсационные действия и их важность.

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

  • Путать саги с двухфазным коммитом - это разные подходы, саги не блокируют ресурсы.
  • Не упоминать идемпотентность компенсаций - повторный вызов refund не должен ломать систему.
  • Считать, что API Gateway обязателен - для внутренних сервисов часто достаточно service mesh.
  • Забывать про outbox: без него события теряются при сбое между записью в БД и публикацией.
  • Говорить о сагах без примера компенсации - это сразу выдаёт поверхностное понимание.

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

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