Взаємодія мікросервісів: Request/Response — коли синхронність має сенс
Коли мікросервіси почали масово замінювати моноліти, одним із перших підходів до їхньої взаємодії став Request/Response. Це знайомий, простий і добре документований механізм: один сервіс надсилає запит — інший обробляє його та повертає відповідь. Наприклад: користувач натискає «замовити», `order-service` запитує у `inventory-service`, чи є товар у наявності, отримує відповідь і продовжує процес. Але чи завжди цей підхід доречний? Коли він працює добре, а коли створює проблеми? У цій статті ми детально розглянемо модель **Request/Response**, її реалізацію на Java (Spring Boot) та JavaScript (Node.js/React), типові помилки, оптимізацію та порівняння з альтернативними підходами. Це керівництво для розробників, які хочуть зрозуміти, як організувати взаємодію між сервісами без втрати продуктивності та надійності.
Зміст статті:
- Що таке Request/Response у мікросервісах?
- Як працює взаємодія за схемою запит-відповідь?
- Реалізація на Java (Spring Boot)
- Реалізація на JavaScript (Node.js + React)
- Переваги та недоліки
- Порівняння з Event-Driven Architecture
- Практичні приклади з життя
- Часто задавані питання (FAQ)
⸻
Що таке Request/Response у мікросервісах?
Це **синхронна взаємодія**, при якій один сервіс (клієнт) надсилає HTTP-запит до іншого (сервер), чекає на відповідь і лише потім продовжує виконання. Найчастіше використовується REST API поверх HTTP.
Основні характеристики
- Синхронність: клієнт блокується, поки не отримає відповідь
- Простота: добре знайомий підхід (як веб-браузер і сервер)
- Чіткий контракт: OpenAPI/Swagger дозволяє точно описати API
- Швидкий результат: швидко реалізувати для MVP
Типові сценарії використання
👉 Приклади:
- Автентифікація: `auth-service` перевіряє токен від `user-service`
- Пошук товару: `catalog-service` запитує дані про ціну у `pricing-service`
- Створення замовлення: `order-service` запитує доступність у `inventory-service`
Request/Response — це «Hello World» взаємодії між сервісами. Просто, зрозуміло, але не завжди безпечне.
⚠️ Важливо: синхронні виклики можуть призвести до **ламцюгового відмовлення**, якщо один сервіс зависне.
⸻
Як працює взаємодія за схемою запит-відповідь?
Процес виглядає так: клієнт формує запит → відправляє його по HTTP → сервер обробляє → повертає відповідь (JSON) → клієнт реагує.
Життєвий цикл одного запиту
- Користувач створює замовлення у UI
- Frontend надсилає POST /api/orders до `order-service`
- `order-service` робить GET /api/inventory/{id} до `inventory-service`
- `inventory-service` перевіряє базу даних
- Повертає { "available": true, "qty": 5 }
- `order-service` створює замовлення та повертає 201 Created
Формати даних
- JSON — найпоширеніший формат
- Protobuf — для високої продуктивності (менший розмір, швидше парсинг)
- XML — рідше, у legacy-системах
⚡ Наприклад: заміна JSON на Protobuf у внутрішніх сервісних викликах скоротила час відповіді на 40% у проекті з високим навантаженням.
Навіть найпростіший запит може стати «бутлячим місцем», якщо сервіс-отримувач повільний або недоступний.
⚠️ Важливо: завжди встановлюйте **таймаути** (напр., 5 секунд) і **retries** (напр., 2 рази).
⸻
Реалізація на Java (Spring Boot)
Spring Boot пропонує кілька способів для виклику інших сервісів: `RestTemplate`, `WebClient`, `OpenFeign`.
Варіант 1: RestTemplate (синхронний)
@Service
public class InventoryClient {
@Autowired
private RestTemplate restTemplate;
public boolean isAvailable(String productId) {
String url = "http://inventory-service/api/inventory/" + productId;
try {
ResponseEntity
response = restTemplate.getForEntity(url, InventoryResponse.class);
return response.getBody().isAvailable();
} catch (HttpClientErrorException e) {
throw new ServiceUnavailableException("Inventory service error");
}
}
}
Варіант 2: OpenFeign (рекомендовано)
@FeignClient(name = "inventory-service", url = "http://inventory-service")
public interface InventoryClient {
@GetMapping("/api/inventory/{id}")
InventoryResponse getInventory(@PathVariable("id") String productId);
}
👉 Плюси: автоматичне створення клієнта, інтеграція з Ribbon/Eureka, легке тестування.
⚠️ Важливо: додайте `@HystrixCommand` або `Resilience4j` для fallback-логіки, якщо сервіс недоступний.
⸻
Реалізація на JavaScript (Node.js + React)
Backend: Node.js (Express + Axios)
// order-service (Node.js)
const axios = require('axios');
app.post('/orders', async (req, res) => {
const { productId } = req.body;
try {
const response = await axios.get(
`http://inventory-service:3001/inventory/${productId}`,
{ timeout: 5000 }
);
if (!response.data.available) {
return res.status(400).json({ error: "Not in stock" });
}
// Create order...
res.status(201).json({ orderId: "..." });
} catch (error) {
res.status(503).json({ error: "Inventory service unavailable" });
}
});
Frontend: React (fetch / axios)
// React Component
const createOrder = async () => {
try {
const response = await axios.post('/api/orders', { productId: "p1" });
console.log("Order created:", response.data.orderId);
} catch (error) {
alert("Помилка створення замовлення");
}
};
JavaScript дає гнучкість, але вимагає обережності: не забувайте про обробку помилок, таймаути та лоадери в UI.
👉 Приклад: ми додали спинер у React, який показується, коли `order-service` чекає відповіді від `payment-service`.
⸻
Переваги та недоліки
Переваги | Недоліки |
---|---|
Простота розуміння | Синхронність = ризик блокування |
Легко тестувати (POSTMAN, curl) | Ланцюги залежностей (A→B→C) |
Добре документовані API (Swagger) | Вразливість до простоїв |
Швидкий старт для MVP | Складно масштабувати при високому навантаженні |
Request/Response — це як автомобіль: зручно, швидко, але не підходить для кожного маршруту.
⚠️ Важливо: не використовуйте синхронні виклики для довгих операцій (напр., генерація звіту). Краще — event-driven або polling.
⸻
Порівняння з Event-Driven Architecture
Критерій | Request/Response | Event-Driven |
---|---|---|
Тип взаємодії | Синхронний | Асинхронний |
Час відповіді | Миттєвий | Із затримкою |
Залежність | Висока (direct call) | Низька (через чергу) |
Складність | Низька | Висока (Kafka, RabbitMQ) |
Приклад | Перевірка наявності | Надсилання email після оплати |
Коли що використовувати?
- Request/Response: коли потрібна відповідь «тут і зараз»
- Event-Driven: коли важлива надійність, автономність, масштабованість
👉 Приклад: ми використовуємо Request/Response для перевірки наявності, але Event-Driven — для оповіщення, бухгалтерії та аналітики.
⚠️ Важливо: найкращі системи використовують **гибридний підхід**.
⸻
Практичні приклади з життя
Кейс 1: Онлайн-магазин (Успіх)
Використовуємо Request/Response між `order-service` та `inventory-service`. Додано таймаути (3 сек), retry (2 рази), fallback («перевіримо пізніше»). Конверсія не впала, система стабільна.
Кейс 2: Фінансова платформа (Хиба)
Сервіс `risk-analysis` синхронно запитував 5 інших сервісів. Середній час відповіді — 8 секунд. Ми переробили на event-driven: тепер аналіз виконується у фоні, користувач отримує статус через WebSocket.
Кейс 3: CRM (Гібрид)
UI → `api-gateway` → `contact-service` (Request/Response). Після збереження — подія `ContactUpdated` → `analytics-service`, `email-service`. Баланс між швидкістю та надійністю.
Правильна взаємодія — це не про технологію, а про розуміння бізнес-потреб.
⸻
Часто задавані питання (FAQ)
Чи можна використовувати Request/Response у великих системах?
Так, але обмежено. Для критичних, часових операцій — так. Для довгих процесів — краще event-driven.
Як уникнути cascade failure?
Використовуйте: таймаути, retries, circuit breaker (Resilience4j), fallback-відповіді.
Чи безпечний HTTP між сервісами?
Тільки через HTTPS (mTLS) або всередині закритої мережі (VPC). Для чутливих даних — додаткова шифрація.
Чи можна комбінувати Request/Response з event-driven?
Так, і це найкраща практика. Наприклад: синхронна валідація + асинхронна обробка.
Як тестувати взаємодію між сервісами?
👉 Засоби: Contract Testing (Pact), MockServer, TestContainers. Тестуйте не лише успішний сценарій, а й помилки, таймаути, відмови.
⸻
Висновки
Request/Response — це **фундаментальний механізм взаємодії мікросервісів**, який залишається актуальним завдяки простоті, швидкості та зрозумілості.
- Використовуйте його для синхронних, часових операцій
- Додавайте таймаути, retries, fallback
- Обирайте OpenFeign (Java) або Axios (JS) для реалізації
- Уникайте глибоких ланцюгів викликів
- Комбінуйте з event-driven для кращої архітектури
Request/Response — не застарілий підхід. Він просто потребує розумного використання.
Готові побудувати надійну взаємодію між сервісами?
Ми проектуємо та реалізуємо взаємодію мікросервісів на Java (Spring Boot) та JavaScript (Node.js, React). Чи це синхронні API, чи асинхронні події — ми обираємо те, що працює.
- Напишіть у Telegram: t.me/name_lucky_lucky
- Email: [email protected]
- Час відповіді: протягом 3 годин