← Назад к вопросам

Какие знаешь подходы для разбиения монолита?

3.0 Senior🔥 151 комментариев
#REST API и микросервисы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подходы для разбиения монолита на микросервисы

Миграция от монолитной архитектуры к микросервисам — сложный и долгий процесс. Вот проверенные стратегии, которые используют крупные компании.

1. Strangler Fig Pattern (Рекомендуется)

Это постепенное перехватывание функционала монолита новыми микросервисами:

// В API Gateway или бизнес-слое
public class RoutingLayer {
    @PostMapping("/api/orders")
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest req) {
        // Проверяем, живёт ли сервис уже отдельно
        if (useNewOrderService()) {
            return orderServiceClient.create(req);  // микросервис
        }
        return legacyOrderService.create(req);  // старый монолит
    }
    
    private boolean useNewOrderService() {
        // Feature flag, A/B тестирование
        return featureToggle.isEnabled("ORDER_SERVICE_V2");
    }
}

Плюсы:

  • Нулевой простой в production
  • Можно откатиться в любой момент
  • Постепенная миграция данных

Минусы:

  • Требует промежуточного слоя (API Gateway)
  • Усложнение логики маршрутизации

2. Domain-Driven Decomposition

Извлекаем сервисы по границам доменов (DDD Bounded Contexts):

Монолит
├── Orders Bounded Context → OrderService
├── Users Bounded Context → UserService
├── Payments Bounded Context → PaymentService
├── Inventory Bounded Context → InventoryService
└── Notifications Bounded Context → NotificationService

Процесс:

  1. Определить доменные границы (нарисовать на доске)
  2. Выделить сущности и агрегаты каждого домена
  3. Обозначить точки взаимодействия (события, API)
  4. Реализовать микросервис с собственной БД
// Orders микросервис
@Service
public class OrderService {
    private final OrderRepository repo;
    private final EventPublisher eventPublisher;
    
    @Transactional
    public OrderCreatedEvent createOrder(CreateOrderCmd cmd) {
        Order order = new Order(cmd.getCustomerId(), cmd.getItems());
        order.setStatus(OrderStatus.CREATED);
        
        repo.save(order);
        
        // Событие для других сервисов
        eventPublisher.publish(new OrderCreatedEvent(order.getId()));
        return ...;
    }
}

Плюсы:

  • Минимальные зависимости между сервисами
  • Чистая архитектура
  • Легче масштабировать

3. Strangler + Seams Model (Продвинутый подход)

Применяем Seams Model (по книге "Working Effectively with Legacy Code") для безопасного выделения функционала:

// Монолит: классический монолитный код
public class OrderService {
    public Order createOrder(OrderRequest req) {
        // Сложная логика с множеством зависимостей
        validateOrder(req);
        calculatePrice(req);
        checkInventory(req);
        processPayment(req);
        sendNotification(req);
        return order;
    }
}

// Применяем Seam: подменяем зависимость
public class OrderServiceWithSeam extends OrderService {
    @Override
    protected void processPayment(OrderRequest req) {
        // Вместо встроенной логики — вызываем микросервис
        paymentServiceClient.process(req);
    }
}

Так же выделяем:

  • Inventory (склад)
  • Notifications (уведомления)
  • Billing (выставление счётов)

4. Database Per Service (Критическое решение)

Каждый микросервис имеет свою БД:

Ордеры        Пользователи    Платежи
  ↓               ↓              ↓
PostgreSQL    PostgreSQL    MongoDB
 (Orders)      (Users)       (Payments)

Это решает:

  • Независимый скейлинг БД
  • Возможность менять СУБД под задачу
  • Автономность сервиса

Проблемы, которые появляются:

  1. Распределённые транзакции — используй Event Sourcing + SAGA pattern:
@Service
public class OrderSagaOrchestrator {
    @Transactional
    public void createOrder(OrderRequest req) {
        // Шаг 1: Создаём ордер
        Order order = orderService.create(req);
        
        try {
            // Шаг 2: Резервируем товар
            inventoryService.reserve(order.getItems());
            
            // Шаг 3: Обрабатываем платёж
            paymentService.charge(order.getPayment());
            
            order.markAsConfirmed();
        } catch (Exception e) {
            // Откатываем все операции (compensating transactions)
            inventoryService.release(order.getItems());
            paymentService.refund(order.getPayment());
            order.markAsFailed();
            throw e;
        }
    }
}
  1. Data Consistency — используй Event Sourcing:
// OrderService публикует события
eventPublisher.publish(new OrderCreatedEvent(
    orderId, customerId, items, createdAt
));

// UserService подписывается и обновляет view
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
    userStatistics.incrementOrderCount(event.getCustomerId());
}

5. Incremental Database Migration

Постепенная миграция данных:

// Фаза 1: читаем из монолита, пишем в оба места
if (newServiceEnabled) {
    newService.createOrder(req);
}
legacyService.createOrder(req);

// Фаза 2: читаем из нового сервиса, пишем в оба
Order order = newService.getOrder(id);  // основной источник
if (order == null) {
    order = legacyService.getOrder(id);  // fallback
}

// Фаза 3: полностью мигрировались
Order order = newService.getOrder(id);

6. API Gateway как точка входа

Критично для управления миграцией:

@Component
public class OrderApiGateway {
    @PostMapping("/api/v1/orders")
    public ResponseEntity<OrderDTO> create(@RequestBody CreateOrderRequest req) {
        if (useNewOrderService) {
            return newOrderServiceClient.create(req);
        }
        return legacyOrderServiceClient.create(req);
    }
}

Рекомендуемый порядок разбиения

  1. Выбери самый независимый модуль (например, Notifications)
  2. Реализуй Strangler + Gateway
  3. Мигрируй данные (двусторонняя синхронизация)
  4. Переключи трафик (используя Feature Flags)
  5. Повтори для следующего модуля

Инструменты, которые помогают

  • Spring Cloud Config — централизованная конфигурация
  • Spring Cloud Gateway — API Gateway
  • RabbitMQ/Kafka — асинхронная коммуникация между сервисами
  • Eureka — service discovery
  • Feature Toggles (Unleash, LaunchDarkly) — контроль миграции
  • ELK Stack — логирование распределённых запросов

Главное

Не старайся разбить всё сразу — начни с малого, проверь на production, затем масштабируй. Монолит разбирают годами, не неделями.

Какие знаешь подходы для разбиения монолита? | PrepBro