Коли моноліт стає в’язницею, або Чому міграція на мікросервіси — це не просто модний тренд
Привіт, DOU-ком’юніті. Ми — Сергій Сучок, Java-розробник і техлід у Ciklum, та Сергій Немчинський, засновник ІТ-школи FoxmindEd. За останні роки нам довелося пройти через справжню одіссею — міграцію десятирічного PHP-моноліту на Java-мікросервіси. І якщо ви думаєте, що це просто «розрізати великий застосунок на кілька маленьких», то ця історія для вас.
Коли код стає археологічним артефактом
Уявіть кодову базу, яка формувалася більше десяти років. Вона пережила кілька поколінь команд, десятки розробників, які приходили і йшли, частково або повністю змінювали підходи, але рідко щось документували. У таких умовах код перетворюється не просто на набір класів і функцій, а на лабіринт, де кожен поворот може виявитися пасткою.
Ми стикалися з методами на 500+ рядків, які виконували бізнес-логіку трьох різних доменів. Legacy-фреймворки, відсутність юніт-тестів, складні залежності між модулями, які навіть неможливо побачити без побудови спеціальних графів. Часто ми мусили просто зупинятись і будувати схему — що звідки викликається, як дані змінюються, і де це ще може вилізти боком.
Найбільшим викликом було те, що будь-яке нове завдання починалось з reverse engineering. Не можна просто «додати фічу», потрібно зрозуміти, як вона вплине на решту — і не лише в UI, а й на базу, кеш, інші частини системи. А якщо ще врахувати, що це все живе в одному великому PHP-файлі з десятками include’ів і без реальної модульності — стає зрозуміло, чому будь-який рефакторинг був майже неможливим.
Мікросервіси — не silver bullet, а інструмент хірурга
Дуже багато команд підходять до мікросервісів як до панацеї. Але правда в тому, що це просто ще один інструмент — складний, дорогий, і небезпечний у невмілих руках.
Ми бачили приклади, коли люди намагалися «розрізати моноліт» за технічним критерієм: окремий мікросервіс для користувачів, для замовлень, для платежів — але без розуміння доменної моделі. Наприклад, коли три сервіси одночасно мають доступ до однієї бази і взаємно оновлюють одні й ті самі таблиці — це вже не мікросервісна архітектура, а shared database monolith.
Ми також бачили мікросервіси, які викликали один одного ланцюжком: сервіс А викликає В, той — С, далі — D. У випадку помилки — ніякої ретрай логіки, відсутній outbox pattern, іноді навіть немає timeouts. Це не мікросервіси, а distributed spaghetti.
І головне — більшість проблем із міграцією виникають не через вибір технологій, а через спробу перенести ментальні моделі з моноліту. Люди шукають, як реалізувати транзакції на кілька баз даних, замість того, щоб подумати про eventual consistency. Вони шукають спосіб поділити Entity, а не домен.
Eventual consistency: коли ідеальність стає ворогом прогресу
Цей блок ми могли б назвати — «прощай ACID, привіт реальність». Моноліт дає нам ілюзію контролю: ви можете відкочувати транзакції, бути впевненими, що дані оновилися всюди або ніде. Але у світі мікросервісів це просто неможливо без втрати переваг масштабованості.
Ми витратили багато часу на розробку процесів, які враховують eventual consistency: outbox pattern, ретрай логіка, ідемпотентність, компенсаційні транзакції. Наприклад, коли користувач оформлює замовлення — у нас не одна «велика» транзакція, а послідовність подій: замовлення створено → резерв товару → підтвердження платежу → відправка email → оновлення статусу.
Важливим моментом стала правильна організація логування й метрик: у світі eventual consistency ви повинні знати, що сталося з кожним кроком. Ви повинні мати можливість відновити подію, перевірити стан кожного мікросервісу та зрозуміти, що саме зламалось. Без observability — ваша система стає чорною скринькою.
Event-driven архітектура: коли сервіси навчаються розмовляти
Переходити до event-driven моделі означає змінити саму суть взаємодії сервісів. Раніше це були виклики API — синхронні, з жорсткою залежністю. Тепер — це події. У нашому випадку ми обрали Kafka, бо вона дозволяє побудувати scalable і fault-tolerant обмін повідомленнями.
Це дозволяє сервісам існувати незалежно. Якщо сервіс складу лежить, сервіс замовлень все одно працює — просто події потрапляють у чергу. Ми реалізували механізми dead-letter queue, з повторною доставкою подій, алертами, і навіть UI для відстеження затриманих повідомлень.
Це вимагає і іншого підходу до тестування. Ми використовуємо contract-тести (наприклад, Pact) для перевірки сумісності подій. Також впровадили CDC (change data capture), щоб перехід на події не порушував логіку інших систем.
Strangler Fig: як задушити моноліт з любов’ю
Повна міграція за одну ітерацію — це практично завжди провал. Тому ми свідомо обрали Strangler Fig підхід. Він передбачає поетапну міграцію частин системи з мінімальним впливом на існуючий функціонал.
Почали з каталогу товарів — мінімум залежностей. Створили окремий мікросервіс, обгорнули старий API Gateway, налаштували A/B маршрутизацію. Потім перенесли замовлення, далі — платежі, користувачів, email-сервіс. Кожен крок ретельно логувався, покривався моніторингом і мав fallback на старий код.
Важливо: Strangler Fig — це не лише технічний патерн, а й організаційний. Ми поступово готували команди до нових практик: DevOps, CI/CD, observability, документації API через OpenAPI. Це дозволило уникнути хаосу, коли всі «переписують одночасно».
Реальність мікросервісів: складність, яку варто приймати
Розробка мікросервісів — це завжди баланс між гнучкістю і складністю. Ви отримуєте:
- Більшу автономність команд. Кожна команда відповідає за свій сервіс і не чекає, поки хтось «випустить реліз».
- Технологічну гнучкість. У нас одні сервіси на Java, інші — на Node.js. Це ок, якщо є чіткі API-контракти.
- Масштабованість. Ми окремо масштабуємо лише сервіс платежів у Black Friday, а не всю систему.
- Fault tolerance. Один сервіс падає — інші працюють. Ви просто кешуєте дані або працюєте з degraded mode.
З іншого боку — це:
- CI/CD пайплайни для кожного сервісу.
- Мережеві затримки.
- Розподілені транзакції.
- Observability стек (Prometheus, Grafana, ELK, Jaeger).
Dependency hell між API-версіями.
Це інший рівень складності, і він не кожному підходить. Але якщо ваша система росте — інакше не вийде.
Навички майбутнього, які потрібні сьогодні
Мікросервіси — це вже не хайп, це нова норма для складних і швидко зростаючих систем. Але ринок потребує не лише тих, хто знає терміни, а тих, хто розуміє принципи: domain-driven design, eventual consistency, resilient architecture, fault isolation.
Це вимагає зміни мислення: не «як швидше закомітити», а «як зробити так, щоб цей сервіс міг жити самостійно, збої не ламали систему, і його могли супроводжувати інші команди».
Тож, якщо ви тільки плануєте свій перехід на мікросервіси — пам’ятайте: це не про технології. Це про архітектуру, культуру, відповідальність і сталість. І так — це складно. Але це варто того.
Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

28 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів