JavaRush /Курси /Модуль 5. Spring /Лекція 169: Як правильно декомпозувати застосунки: зони в...

Лекція 169: Як правильно декомпозувати застосунки: зони відповідальності мікросервісів

Модуль 5. Spring
Рівень 11 , Лекція 8
Відкрита

Декомпозиція — це процес розбиття великої системи (наприклад, моноліту) на менші, незалежні компоненти (у нашому випадку — мікросервіси). Ці компоненти повинні бути автономними, керованими і обслуговуваними окремо один від одного. Однак усе не так просто: розділити застосунок на мікросервіси — це не те саме, що розрізати пиріг на рівні шматки. Тут не можна діяти наосліп: важливо враховувати бізнес-логіку, межі контексту і мінімізацію звʼязків між сервісами.

Якщо ви колись намагалися зібрати шафу IKEA без інструкції, то приблизно уявляєте, якого масштабу хаос може виникнути при неправильній декомпозиції. Ми повинні бути впевнені, що кожна частина системи має чітку зону відповідальності і взаємодіє з іншими компонентами мінімально, щоб не перетворитися на "розподілений моноліт".


Принципи декомпозиції

  1. Розділення за бізнес-функціями, а не технічними компонентами. Один з найпоширеніших антипатернів при переході на мікросервіси — спроба декомпозувати застосунок по шарах (UI, бізнес-логіка, база даних). Це примножує залежності між сервісами і створює додаткові проблеми при їхньому незалежному розгортанні. Наприклад, замість того щоб створювати один сервіс для всіх даних, пов'язаних із клієнтами, і інший для всіх даних про замовлення, краще створити окремі сервіси для управління клієнтами (Customer Service) і замовленнями (Order Service). Кожен з них буде самостійно обробляти свої дані, а взаємодія між сервісами звядеться до мінімуму.
  2. Уникайте "важких" (fat) мікросервісів. Іноді спокуса скинути всю пов'язану логіку в один мікросервіс велика. Але тоді такий сервіс стає складно масштабованим і підтримуваним, перетворюючись на моноліт всередині мікросервісної архітектури. Це як валіза без ручки: і нести важко, і викинути шкода.
  3. Слабка зв'язаність (Loose Coupling). Мікросервіси повинні бути максимально незалежними один від одного. Будь-яка взаємодія між ними має бути мінімізована і формалізована через інтерфейси, такі як API або події. Це спрощує тестування, оновлення і масштабування окремих компонентів.
  4. Висока когезія (High Cohesion). Код в одному мікросервісі повинен бути пов'язаний спільними цілями. Це як з друзями: з однією компанією круто піти в кіно, а з іншою — обговорити мікросервіси. А от змішувати їх не варто, хтось обов'язково буде нудьгувати.

Визначення меж мікросервісів

Найпопулярніший підхід у декомпозиції мікросервісів — використання концепції Bounded Context, запропонованої в рамках Domain-Driven Design (DDD). Кожен мікросервіс має обслуговувати одну конкретну предметну область (або підмножину області), надаючи чітко визначені механізми взаємодії з іншими сервісами.

Приклад:

  • Клієнти (Customer Service)
  • Замовлення (Order Service)
  • Платежі (Payment Service)
  • Сповіщення (Notification Service)

Так може бути влаштований, наприклад, інтернет-магазин. Замість одного моноліту, який робить усе (керує клієнтами, замовленнями, платежами, сповіщеннями), ми створюємо окремі мікросервіси, кожен з яких відповідає за конкретну бізнес-потребу.


Як уникнути поширених антипатернів?

  1. Анархічна декомпозиція. Коли немає стратегії, розробники просто створюють мікросервіси "як вийде". Проблема в тому, що це призводить до розподілених монолітів, де системи занадто тісно пов'язані і з'являються складнощі з масштабуванням.
  2. Дублювання даних. Дублювання даних між сервісами — неминуче, але його потрібно мінімізувати. Наприклад, сервіс замовлень не повинен зберігати повні дані клієнта, достатньо ID клієнта, щоб запросити дані у Customer Service.
  3. Надмірна деталізація. Не варто розробляти надто дрібні мікросервіси. Якщо ви намагаєтеся зробити окремий сервіс для кожної дії (наприклад, окремий сервіс для "додати товар у кошик"), це викличе величезні накладні витрати на комунікацію.

Практична вправа: декомпозиція інтернет-магазину

Припустимо, ви розробляєте великий інтернет-магазин. Як його розділити на мікросервіси?

1. Визначаємо основні області (Business Domains):

  • Управління клієнтами (Customer Management)
  • Управління каталогом товарів (Product Catalog)
  • Управління замовленнями (Order Management)
  • Обробка платежів (Payment Processing)
  • Управління сповіщеннями (Notifications)

2. Розділяємо дані: Кожен мікросервіс має бути власником своїх даних:

  • Customer Service зберігає інформацію про клієнтів (ім'я, email, історію замовлень тощо).
  • Product Catalog Service керує інформацією про товари (назва, опис, ціна, наявність на складі).
  • Order Service обробляє замовлення (дані про замовлення, статуси).
  • Payment Service відповідає за обробку транзакцій (оплата, повернення).
  • Notification Service надсилає сповіщення (email, SMS).

3. Визначаємо взаємодію:

  • Customer Service передає інформацію про клієнтів в Order Service.
  • Order Service запитує дані про товари з Product Catalog Service.
  • Order Service передає запити на оплату в Payment Service.
  • Payment Service передає дані про успішні платежі в Order Service.
  • Всі події можуть викликати сповіщення через Notification Service.

4. Обираємо підходи до взаємодії

  • Для синхронної взаємодії використовуємо REST API. Для асинхронної — наприклад, Kafka: події, такі як "нове замовлення створено" або "платіж пройшов успішно", можуть публікуватися в Kafka, щоб їх могли обробляти інші мікросервіси.

Кроки для декомпозиції моноліту в мікросервіси

  1. Аналіз поточної системи
    • Спробуйте виділити основні бізнес-функції вашого моноліту.
  2. Визначте зони відповідальності
    • Об'єднайте пов'язані функціональні модулі в єдину область відповідальності.
  3. Розділіть бази даних
    • Розподіліть дані між сервісами так, щоб кожен сервіс керував своєю базою даних.
  4. Забезпечте взаємодію
    • Оберіть між синхронною (REST) або асинхронною (Kafka) взаємодією.
  5. Міграція функціональності
    • Поступово переносіть функціональність з моноліту в мікросервіси.
  6. Тестування
    • Переконайтеся, що нові модулі працюють коректно і взаємодіють один з одним.

Приклад: REST API між сервісами

Для взаємодії між Order Service та Product Catalog Service:


// REST-клієнт Order Service для отримання даних про товари
@RestController
@RequestMapping("/order")
public class OrderController {

    private final RestTemplate restTemplate;

    public OrderController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @PostMapping
    public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
        // Відправка запиту в Product Catalog Service
        ResponseEntity<Product> productResponse = restTemplate.getForEntity(
            "http://product-service/product/" + orderRequest.getProductId(),
            Product.class
        );

        if (productResponse.getStatusCode().is2xxSuccessful()) {
            // Обробка замовлення
            return ResponseEntity.ok("Order created successfully!");
        } else {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Product not found");
        }
    }
}

Для асинхронної передачі подій використовуйте Kafka:


// Публікація події "Order Created" в Kafka
@Service
public class OrderEventPublisher {

    private final KafkaTemplate<String, String> kafkaTemplate;

    public OrderEventPublisher(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void publishOrderCreatedEvent(Order order) {
        kafkaTemplate.send("orders", order.toString());
    }
}

Висновки

Правильна декомпозиція вимагає глибокого розуміння ваших бізнес-процесів, роботи системи і можливих вузьких місць. Сервіс має бути достатньо великим, щоб виконувати змістовне завдання, але досить простим для розробки, тестування і деплою. Тримайте в голові основний принцип: один мікросервіс — одна бізнес-функція.

Подібно злагодженій роботі кухні ресторану, де кожен кухар відповідає за свою ділянку роботи, мікросервіси незалежно виконують свої задачі, але разом створюють цілісну систему.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ