Какие ключевые паттерны используются в микросервисной архитектуре?

Ответ

В микросервисной архитектуре используется множество паттернов для решения типичных проблем распределенных систем. Вот некоторые из ключевых:

  1. API Gateway: Единая точка входа для всех клиентских запросов. Он маршрутизирует запросы к нужным сервисам, а также может выполнять аутентификацию, логирование, кэширование и rate limiting.

  2. Service Discovery: Механизм для автоматического обнаружения сетевого местоположения (IP-адрес и порт) экземпляров сервисов. Позволяет сервисам находить друг друга без жестко прописанных адресов. Примеры: Consul, etcd, Zookeeper.

  3. Circuit Breaker (Предохранитель): Защищает систему от каскадных сбоев. Если сервис-зависимость начинает возвращать ошибки, Circuit Breaker "размыкается" и перестает отправлять на него запросы на некоторое время, возвращая ошибку немедленно. Это дает сбойному сервису время на восстановление.

  4. Database per Service: Каждый микросервис управляет своей собственной базой данных. Это обеспечивает слабую связанность (loose coupling), так как изменения в схеме данных одного сервиса не влияют на другие.

  5. Saga Pattern: Паттерн для управления распределенными транзакциями. Вместо одной большой ACID-транзакции используется последовательность локальных транзакций в каждом сервисе. Если одна из них сбоит, выполняются компенсирующие транзакции для отката изменений.

  6. CQRS (Command Query Responsibility Segregation): Разделение операций на команды (изменение данных) и запросы (чтение данных). Это позволяет независимо масштабировать и оптимизировать модели для чтения и записи.

Пример реализации Circuit Breaker в Go:

import (
    "time"
    "github.com/sony/gobreaker"
)

var cb *gobreaker.CircuitBreaker

func init() {
    settings := gobreaker.Settings{
        Name:        "my-external-service",
        MaxRequests: 1,
        Timeout:     5 * time.Second,
        ReadyToTrip: func(counts gobreaker.Counts) bool {
            return counts.ConsecutiveFailures > 3
        },
    }
    cb = gobreaker.NewCircuitBreaker(settings)
}

func CallMyService() (interface{}, error) {
    body, err := cb.Execute(func() (interface{}, error) {
        // Логика вызова внешнего сервиса
        return externalAPI.GetData()
    })
    if err != nil {
        return nil, err
    }
    return body, nil
}