> Какие паттерны микросервисов использовались, например саги, 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:
GOtype SagaCoordinator struct {paymentClient *PaymentClientdeliveryClient *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 с агрегацией:
GOfunc (g *Gateway) GetOrderDetails(w http.ResponseWriter, r *http.Request) {orderID := chi.URLParam(r, "id")// параллельные вызовы к сервисамvar order Ordervar payment Paymentvar delivery Deliveryvar wg sync.WaitGroupwg.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: без него события теряются при сбое между записью в БД и публикацией.
- Говорить о сагах без примера компенсации - это сразу выдаёт поверхностное понимание.
> Похожие задачи по backend
Была ли важна атомарность изменений в хранилище и отправки сообщений
Использовали ли транзакции при отправке сообщений в брокер
Кто принимал решения по архитектуре сервиса лояльности
Как устроена разработка сервисов: существующие или с нуля
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью