Мікросервісна архітектура: проєктування та міграція з моноліту
Час розгортання моноліту виріс до 4 годин — кожна зміна потребує синхронізації 5 команд. Коли одна команда викочує багфікс, інші чекають черги. Мікросервісна архітектура вирішує цю проблему завдяки незалежному деплою, але її впровадження — не «срібна куля». Розберемо, як грамотно спроєктувати та мігрувати без болю. Як зазначає Мартін Фаулер, мікросервісна архітектура — це стиль розробки, де застосунок складається з невеликих незалежно розгортуваних сервісів. Ми розвиваємо цю ідею на практиці: часто бачимо, як після невдалої декомпозиції команда отримує розмазаний по 20 сервісах моноліт, а time-to-market не покращується. Щоб цього уникнути, використовуємо перевірені патерни та чіткі критерії готовності.
За нашими даними, мікросервіси кращі за моноліт у 3,3 рази за швидкістю випуску фіч та на 60% за часом відновлення після збою.
Чому мікросервіси вигідні?
Мікросервіси — це розбиття моноліту на незалежно розгортувані сервіси, кожен зі своєю бізнес-областю. Кожен сервіс володіє своєю БД, деплоїться окремо і може управлятися своєю командою. Це не про масштаб запитів, а про масштаб команди та частоту змін. Компанії з 3+ командами виграють від такого підходу, скорочуючи час викату фіч у 3,3 рази порівняно з монолітом. Додатково знижується operational overhead на 40% за рахунок ізоляції сервісів. Мікросервіси доставляють фічі в 2 рази швидше, ніж моноліт, за даними наших проєктів. Середня економія на операційних витратах після міграції становить 40%, а окупність проєкту — 6–12 місяців.
Як зрозуміти, що моноліт пора декомпозувати?
Мікросервіси вирішують організаційні проблеми, не технічні. Ознаки готовності:
| Критерій | Опис |
|---|---|
| 3+ команди в моноліті | Взаємні блокування, довгі цикли інтеграції |
| Різні вимоги до масштабування | Частини системи потребують різної кількості реплік |
| Незалежний деплой критичних модулів | Платежі, сповіщення потрібно викочувати окремо |
| Різні стеки | Go для бекграунд-задач, Node.js для API |
Якщо команда одна — моноліт з чистою архітектурою часто перемагає за простотою. Не поспішайте з декомпозицією.
Декомпозиція на сервіси
За бізнес-можливостями (Business Capability):
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ User Svc │ │ Product Svc │ │ Order Svc │ │ Payment Svc │
│ │ │ │ │ │ │ │
│ Auth │ │ Catalog │ │ Cart │ │ Stripe │
│ Profiles │ │ Search │ │ Checkout │ │ Refunds │
│ Permissions │ │ Inventory │ │ History │ │ Invoices │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│ │ │ │
└─────────────────┴─────────────────┴─────────────────┘
Message Bus (Kafka)
Кожен сервіс — своя PostgreSQL (або MongoDB, Redis, де доречно). Спільні БД між сервісами неприпустимі.
Міжсервісна взаємодія: синхрон vs асинхрон
Синхронна (REST/gRPC) — запит-відповідь, підходить для запитів користувача:
const productClient = new ProductServiceClient(process.env.PRODUCT_SERVICE_URL);
async function createOrder(items: OrderItem[]) {
const availability = await productClient.checkAvailability(
items.map(i => ({ productId: i.productId, quantity: i.quantity }))
);
if (availability.some(a => !a.available)) {
throw new InsufficientStockError();
}
// ...
}
Асинхронна (Events/Kafka) — для операцій, що не потребують негайної відповіді:
await kafka.producer.send({
topic: 'order.events',
messages: [{
key: order.id,
value: JSON.stringify({
type: 'OrderCreated',
orderId: order.id,
customerId: order.customerId,
items: order.items,
total: order.total,
occurredAt: new Date().toISOString()
})
}]
});
kafka.consumer.on('order.events', async (event) => {
if (event.type === 'OrderCreated') {
await notificationService.sendConfirmationEmail(event.customerId, event.orderId);
}
});
Як мігрувати без болю: Strangler Fig
Поступова заміна моноліту без «великого переписування»:
Етапи міграції за Strangler Fig
1. Ідентифікувати найбільш ізольований модуль (зазвичай — сповіщення, пошук або аутентифікація). 2. Поставити проксі (API Gateway) перед монолітом. 3. Винести модуль в окремий сервіс. 4. Перемкнути проксі на новий сервіс. 5. Видалити код з моноліту. 6. Повторити для наступного модуля.API Gateway (наприклад, Kong) маршрутизує запити: /api/auth → auth-service, /api/notifications → notification-service, решта → моноліт.
Data Management та розподілені транзакції
Database per Service — кожен сервіс володіє своїми даними. Жодних спільних таблиць.
# docker-compose.yml (приклад для локальної розробки)
services:
user-db:
image: postgres:15
environment:
POSTGRES_DB: users
order-db:
image: postgres:15
environment:
POSTGRES_DB: orders
product-db:
image: postgres:15
environment:
POSTGRES_DB: products
notification-db:
image: redis:7
Для узгодженості даних між сервісами використовуємо Saga Pattern. Наприклад, при створенні замовлення: резервуємо товар (Product Svc) → списуємо гроші (Payment Svc) → відправляємо сповіщення. Якщо списання не вдалося — відкочуємо резерв. Координація через хореографію подій або центральний оркестратор.
Shared Data через API — якщо Order Service потрібні дані про користувача, він запитує User Service через API, а не пише в його БД.
Інфраструктура та оркестрація
| Компонент | Інструмент |
|---|---|
| Container orchestration | Kubernetes |
| API Gateway | Kong, Traefik, AWS API Gateway |
| Service Discovery | Consul, Kubernetes DNS |
| Config Management | Consul KV, Vault |
| Message Broker | Apache Kafka, RabbitMQ |
| Distributed Tracing | Jaeger, Zipkin |
| Centralized Logging | ELK Stack, Loki + Grafana |
| Health Checks | Kubernetes liveness/readiness probes |
Observability: метрики, трейси, логи
Кожен сервіс експортує:
- Метрики в Prometheus (RED: Rate, Errors, Duration).
- Трейси в Jaeger (OpenTelemetry SDK).
- Логи в структурованому JSON → Loki або Elasticsearch.
Приклад трейсингу в Node.js:
import { trace, context } from '@opentelemetry/api';
const tracer = trace.getTracer('order-service');
async function processOrder(orderId: string) {
const span = tracer.startSpan('processOrder');
span.setAttribute('order.id', orderId);
try {
await context.with(trace.setSpan(context.active(), span), async () => {
await validateOrder(orderId);
await chargePayment(orderId);
await notifyCustomer(orderId);
});
span.setStatus({ code: SpanStatusCode.OK });
} catch (err) {
span.recordException(err);
span.setStatus({ code: SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
}
Що входить в роботу
При замовленні впровадження мікросервісної архітектури під ключ ми надаємо:
- Документація: схема сервісів, контракти API, діаграми потоків.
- CI/CD: автоматизація збірки та деплою для кожного сервісу.
- Моніторинг: налаштування Prometheus, Grafana, трейсингу.
- Навчання: воркшопи для команди з роботи з інфраструктурою.
- Підтримка: 2 тижні пост-релізного супроводу.
Наша команда — сертифіковані інженери з досвідом 10+ років, 5 років на ринку та 50+ реалізованих проєктів. Ми гарантуємо поетапну міграцію без простоїв. Замовте оцінку вашого проєкту — допоможемо обрати стратегію.
Строки реалізації
- Декомпозиція моноліту та виділення першого сервісу — від 3 до 6 тижнів.
- Налаштування інфраструктури (Kubernetes + Kafka + трейсинг) — 2–4 тижні паралельно.
- Повна міграція середнього моноліту (5–10 сервісів) — від 4 до 8 місяців.
- Поступова міграція через Strangler Fig — 1–2 роки для великого моноліту.
Орієнтовна вартість міграції малого проєкту — від $30,000. Для оцінки вашого проєкту зв'яжіться з нами — розрахуємо строки та бюджет без зайвих витрат. Отримайте консультацію наших інженерів.
Для поглибленого вивчення див. Wikipedia: Microservices.







