Sobes.tech
Senior

Faraz qilaylik, bizning mikroxizmatimiz tashqi API, masalan, to'lov o'tkazish tizimiga kirishi kerak, lekin u kutilmaganda juda sekinlashadi yoki umuman yiqilib ketadi. Bunday qo'shnilardan odatda qanday himoya qilasiz, shunda butun xizmatimiz yiqilmaydi?

sobes.tech AI

AIdan javob

Чтобы защитить микросервис от зависимостей, которые могут тормозить или падать (например, внешнее API платежной системы), обычно применяют следующие подходы:

  1. Таймауты и ретраи — задавать разумные таймауты на запросы и ограниченное число повторных попыток.

  2. Circuit Breaker (автоматический выключатель) — если внешний сервис часто падает или отвечает медленно, circuit breaker временно блокирует вызовы к нему, чтобы не нагружать систему и не ждать долго.

  3. Bulkhead (отсекатель) — изолировать ресурсы, выделяя отдельные пулы потоков или горутин для вызовов к внешнему сервису, чтобы сбой не распространялся.

  4. Fallback (запасной вариант) — при недоступности внешнего сервиса возвращать заранее подготовленные данные или заглушки.

  5. Мониторинг и алерты — отслеживать состояние вызовов и быстро реагировать.

В Go для реализации circuit breaker и таймаутов часто используют библиотеки вроде github.com/sony/gobreaker или github.com/afex/hystrix-go.

Пример с таймаутом и circuit breaker:

import (
    "context"
    "net/http"
    "time"

    "github.com/sony/gobreaker"
)

var cb *gobreaker.CircuitBreaker

func init() {
    cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{
        Name:        "PaymentAPI",
        MaxRequests: 5,
        Interval:    60 * time.Second,
        Timeout:     30 * time.Second,
        ReadyToTrip: func(counts gobreaker.Counts) bool {
            return counts.ConsecutiveFailures > 3
        },
    })
}

func callPaymentAPI(ctx context.Context, url string) (*http.Response, error) {
    result, err := cb.Execute(func() (interface{}, error) {
        req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
        client := &http.Client{
            Timeout: 5 * time.Second, // таймаут на запрос
        }
        return client.Do(req)
    })

    if err != nil {
        // fallback или обработка ошибки
        return nil, err
    }

    return result.(*http.Response), nil
}

Таким образом, при проблемах с внешним сервисом наш микросервис не зависнет и сможет корректно обработать ситуацию.