Пора поговорити про те, як ці автономні вчені-мікросервіси все ж таки «спілкуються» один з одним. І тут, як у житті, є два популярні способи: говорити напряму (синхронно) або надсилати листи/повідомлення (асинхронно).
Уяви собі звичайний робочий процес в офісі. Коли тобі терміново потрібна інформація від колеги, ти підходиш до нього напряму або дзвониш (синхронна комунікація). Коли завдання не горить, ти надсилаєш email і спокійно займаєшся іншими справами, поки чекаєш відповідь (асинхронна комунікація). Вибір способу спілкування залежить від терміновості й важливості питання.
Так само й мікросервіси можуть спілкуватися різними способами в залежності від їх завдань. Наприклад:
- Якщо мікросервісу A потрібна негайна відповідь від мікросервісу B, він звертається до нього напряму через REST API.
- Якщо мікросервісу A неважлива терміновість відповіді, він відправить повідомлення через брокера (наприклад, Kafka).
Отже, синхронна чи асинхронна комунікації — це два фундаментальні підходи, які забезпечують взаємодію між сервісами в мікросервісній архітектурі.
Синхронна комунікація через REST API
Синхронна комунікація означає, що сервіс робить запит і чекає відповіді від іншого сервісу. Це схоже на телефонний дзвінок: ти дзвониш другу і чекаєш, поки він відповість. Якщо він не відповідає, дзвониш знову або кидаєш слухавку.
У світі мікросервісів найпопулярнішим способом синхронної комунікації є REST API.
Приклад синхронної взаємодії з REST
Припустимо, ти розробляєш систему замовлення їжі. У тебе є два мікросервіси:
OrderService— відповідає за обробку замовлень.PaymentService— відповідає за обробку платежів.
Сценарій: при оформленні клієнтом замовлення OrderService повинен викликати PaymentService, щоб перевірити, чи достатньо коштів для оплати. Ось як це може виглядати:
// OrderService: Виклик REST API PaymentService (синхронний запит)
@RestController
@RequestMapping("/orders")
public class OrderController {
@PostMapping
public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
// Логіка створення замовлення
// Надсилаємо запит в PaymentService
RestTemplate restTemplate = new RestTemplate();
String paymentUrl = "http://localhost:8081/payment/validate";
PaymentResponse paymentResponse = restTemplate.postForObject(paymentUrl, orderRequest, PaymentResponse.class);
if (paymentResponse.isPaymentValid()) {
return ResponseEntity.ok("Order created successfully.");
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Payment failed.");
}
}
}
Переваги синхронної комунікації
- Проста реалізація: REST API — це стандарт, який багато розробників вже розуміють, а інструменти (наприклад, Spring RestTemplate і WebClient) суттєво спрощують роботу.
- Прямий доступ: сервіс викликає інший сервіс напряму, отримує відповідь одразу.
- Звичність: REST API широко застосовується і зрозумілий як розробникам, так і менеджерам.
Обмеження синхронної комунікації
- Часова залежність: якщо
PaymentServiceнедоступний, тоOrderServiceтакож «зависає», що може порушити роботу всієї системи. - Проблеми з масштабуванням: якщо навантаження на
OrderServiceзбільшиться,PaymentServiceтакож має справлятися з великою кількістю запитів. - Підвищена затримка: кожен виклик REST — це час очікування, що може уповільнити загальну продуктивність.
Коли використовувати синхронну комунікацію?
- Коли потрібна миттєва відповідь.
- Коли залежність між сервісами тісна (наприклад, перевірка платіжних даних).
- Коли відмови в одному сервісі критично впливають на інший.
Асинхронна комунікація з використанням повідомлень
Асинхронність передбачає, що один сервіс відправляє повідомлення іншому через брокера (наприклад, Kafka, RabbitMQ або ActiveMQ) і не чекає негайної відповіді. Це більше схоже на відправку електронного листа: ти написав повідомлення і продовжив займатися своїми справами, а отримувач відповість, коли зможе.
Основні концепції асинхронної комунікації
- Брокери повідомлень (Message Brokers): зазвичай використовується посередник, наприклад, Kafka, який зберігає і доставляє повідомлення.
- Продюсер і Консьюмер: сервіс-відправник називається продюсером (producer), а сервіс-одержувач — консьюмером (consumer).
- Топіки: повідомлення відправляються в "топіки" (topics), які діють як поштові скриньки.
Приклад асинхронної взаємодії через Kafka
Продовжимо приклад з OrderService і PaymentService. Припустимо, ми хочемо відправити замовлення на оплату асинхронно.
Публікуємо повідомлення (Продюсер):
// OrderService: Відправка повідомлення в Kafka
@RestController
@RequestMapping("/orders")
public class OrderController {
private final KafkaTemplate<String, OrderRequest> kafkaTemplate;
public OrderController(KafkaTemplate<String, OrderRequest> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
@PostMapping
public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
kafkaTemplate.send("payment-topic", orderRequest); // Надсилаємо повідомлення
return ResponseEntity.ok("Order created successfully. Payment will be processed.");
}
}
Обробляємо повідомлення (Консьюмер):
// PaymentService: Отримання повідомлення з Kafka
@Component
public class PaymentConsumer {
@KafkaListener(topics = "payment-topic", groupId = "payment-group")
public void handlePayment(OrderRequest orderRequest) {
// Логіка обробки платежу
System.out.println("Processing payment for order: " + orderRequest.getOrderId());
}
}
Переваги асинхронної комунікації
- Зменшення залежності: сервіси працюють незалежно один від одного. Навіть якщо
PaymentServiceвимкнений,OrderServiceпродовжить працювати. - Підвищена масштабованість: брокери повідомлень, такі як Kafka, можуть обробляти величезні обсяги даних.
- Гнучкість взаємодії: кілька консьюмерів можуть підписатися на один топік, що зручно для складних систем.
Обмеження асинхронної комунікації
- Складність реалізації: потрібна настройка брокера повідомлень і обробка помилок (наприклад, недоставлених повідомлень).
- Відсутність негайної відповіді: якщо успішність операції критична, це може бути проблемою.
- Гарантії доставки: не всі брокери повідомлень підтримують сувору гарантію доставки.
Коли використовувати асинхронну комунікацію?
- Коли задача не потребує негайного завершення (наприклад, відправка сповіщень).
- Коли потрібно роз’єднати сервіси і зменшити їх взаємозалежність.
- Коли потрібно ефективно обробляти великий обсяг даних.
Вибір між синхронною і асинхронною комунікацією
Вибір підходу залежить від конкретного сценарію. Ось кілька рекомендацій:
| Критерій | Синхронна (REST) | Асинхронна (Повідомлення) |
|---|---|---|
| Негайність відповіді | Потрібна | Не потрібна |
| Залежність між сервісами | Висока | Низька |
| Обсяг даних | Невеликий | Великий |
| Масштабованість | Обмежена | Висока |
| Складність реалізації | Низька | Висока |
Типові помилки при використанні підходів
- Використання REST для задач, які не потребують негайної відповіді, веде до збільшення затримок і залежностей.
- Ігнорування обробки помилок в асинхронній комунікації може призвести до втрати повідомлень.
- Неправильне проектування топіків Kafka (наприклад, занадто багато продюсерів і консьюмерів на одному топіку) створює хаос.
Щоб уникнути цих проблем, ретельно аналізуйте вимоги системи і обирайте підхід, який найкраще відповідає вашим цілям.
На цьому етапі ми вже розібралися, як мікросервіси можуть взаємодіяти один з одним за допомогою синхронного REST і асинхронних повідомлень. У наступній лекції ми почнемо заглиблюватися в декомпозицію додатків для мікросервісної архітектури. Побачимось у коді! 😉
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ