
Мікросервіси чи моноліт: як обрати правильну архітектуру
- microservices vs monolith
- software architecture
- monolithic architecture
- microservices architecture
- system design
- scalable software
- distributed systems
- enterprise software architecture
- modular monolith
- application modernization

Вибір між монолітом і мікросервісами визначає, де саме система сплачуватиме ціну за узгодження роботи. У моноліті більшість змін координують у межах однієї кодової бази, одного процесу, одного розгортання й часто однієї транзакційної межі даних. У мікросервісах узгодження переходить у чіткі контракти між сервісами, мережеву взаємодію, повідомлення, незалежні випуски, розподіл відповідальності та супровід. Жоден підхід не усуває складності: кожен лише переносить її туди, де певній організації зручніше з нею працювати.
Архітектура має допомагати компанії безпечно змінювати продукт із потрібною швидкістю. Порівнюйте реальні обмеження: сталість предметної області, кількість і самостійність команд, конфлікти під час випусків, різницю в навантаженні, вимоги до узгодженості даних, доступності й відновлення, регуляторне відокремлення, спроможність платформи та повну вартість супроводу. Сам обсяг трафіку рідко визначає модель. Якісно спроєктований застосунок здатен масштабуватися задовго до того, як йому знадобляться десятки сервісів, тоді як залежність між командами іноді виправдовує поділ раніше, ніж обчислювальне навантаження.
Для багатьох нових продуктів практичним початковим вибором є модульний моноліт: єдина система для розгортання зі строгими внутрішніми межами, чіткою відповідальністю та інтерфейсами, які не дозволяють кожному модулю напряму звертатися до будь-якої таблиці. Така модель спрощує локальне розроблення, транзакції, тестування й супровід, водночас залишаючи шлях до подальших змін. Переходьте до мікросервісів, коли окремій частині системи справді потрібні власна команда, можливість незалежно розгортатися й масштабуватися, ізоляція або окрема технологія, а користь від цього виправдовує постійні витрати розподіленої системи.
Ставтеся до архітектурного рішення як до гіпотези, яку слід переглядати. Зафіксуйте обмеження, очікувану користь, витрати на супровід, відповідального, докази досягнення результату та дату повторного розгляду. Так архітектура залишатиметься пов’язаною зі спостережуваними потребами продукту й організації, навіть коли вони змінюються.
Моноліт — спосіб розгортання, а не вада проєктування
Монолітний застосунок збирають і випускають як єдиний пакет. Це нічого не говорить про якість його внутрішньої будови. Модульний моноліт може об’єднувати пов’язані можливості в цілісні модулі, відкривати вузькі інтерфейси, закріплювати дані за предметними областями, запобігати циклічним залежностям і відокремлювати бізнес-правила від засобів взаємодії із зовнішнім світом. Одна збірка може містити багато добре керованих меж.
Переваги в експлуатації вагомі: одне локальне середовище виконання, менше ланцюжків розгортання, прямі виклики замість ненадійної мережі, простіше відстеження запитів, атомарні транзакції там, де вони доречні, менше поєднань версій і менша кількість складників платформи. Невеликі команди можуть приділяти більше уваги цінності для клієнта, розумінню предметної області та якості. Горизонтальне масштабування за допомогою копій, кешування, черги, налаштування бази даних, окремі моделі читання й фонові обробники розв’язують багато завдань масштабування без виділення сервісів.
Проблеми спричиняє некерована зв’язаність, а не саме слово «моноліт». Спільні таблиці, доступні з будь-якого місця, імпорти між модулями, глобальний стан, тривале складання, крихкі випуски й нечітка відповідальність перетворюють кожну зміну на переговори. Вимірюйте частку невдалих змін, тривалість тестів, ризик розгортання, конкуренцію за найнавантаженіші частини та залежності між модулями. Спочатку зміцніть внутрішні межі й лише потім додавайте мережеву взаємодію. Події можуть послаблювати зв’язаність як у межах одного розгортання, так і між кількома; докладніше — у матеріалі «Подієво-орієнтована архітектура з NestJS». CQRS також не залежить від кількості одиниць розгортання; дивіться «CQRS із NestJS: переваги та компроміси».
Незалежність мікросервісів має ціну розподіленої системи
Мікросервіси поділяють систему на сервіси, які можна розгортати незалежно й які відповідають окремим можливостям бізнесу. Корисний сервіс уміщує змістовну бізнес-логіку, володіє своїми даними та має команду, відповідальну за нього від проєктування до роботи в промисловому середовищі. Він може розвиватися без синхронного випуску всієї платформи. Кінцева точка HTTP в окремому контейнері, що користується спільною базою даних і випускається за спільним календарем, лише розносить компоненти, але не дає їм незалежності.
Користь з’являється, коли різні межі мають різні потреби: кільком командам необхідно випускати зміни самостійно; певне навантаження потребує особливого масштабування, захисту, доступності, відновлення або технології; збій потрібно ізолювати; чи предметна область має змінюватися за власним графіком. Ціна проявляється в кожному виклику та кожній операції: затримках, перевищенні часу очікування, повторних спробах, дубльованих і переставлених повідомленнях, часткових збоях, узгодженості даних із затримкою, розвитку схем, автентифікації сервісів, їх пошуку й маршрутизації, спостережуваності, координації під час інцидентів і додатковій інфраструктурі.
Незалежне розгортання потребує суворої сумісності. Сервісам потрібні закріплені за ними контракти, перевірки з урахуванням потреб споживачів, правила версіювання й припинення підтримки, ідемпотентність, обмежена кількість повторних спроб, наскрізні ідентифікатори, контроль навантаження та інструкції з відновлення. Кожен сервіс має розгортатися й працювати без спільної процедури, яку щоразу узгоджують кілька команд. Якщо кожна зміна проходить через кілька сховищ коду, чекає на спільне випробувальне середовище й виходить лише разом з усіма, результатом стає розподілений моноліт із більшою кількістю можливих відмов.
Порівнюйте компроміси, що справді впливають на випуск змін
Випуск змін: моноліт має єдиний шлях для змін і потребує менше початкових витрат; мікросервіси зменшують потребу в узгодженні лише тоді, коли самостійні команди відповідають за сталі межі. Дані: у моноліті можна використовувати локальні атомарні транзакції; для взаємодії між сервісами потрібні чітка відповідальність за дані, події або робочі процеси, звіряння стану й компенсувальні операції. Тестування: поведінку одного процесу простіше відтворити; розподілена система потребує перевірок контрактів, взаємодії, стійкості та роботи в умовах, близьких до промислових.
Надійність: у моноліті менше мережевих причин відмови, але одне розгортання може зачепити більшу частину системи. Сервіси здатні ізолювати збій, однак залежності спричиняють ланцюгові відмови, якщо не спроєктувати й не перевіряти обмеження часу очікування, скидання надмірного навантаження, керування вхідним потоком і режими обмеженої роботи. Масштабування: моноліт масштабують як єдине ціле, хоча фонові обробники та шляхи читання можуть відрізнятися; сервіси масштабують окремо, але це має сенс лише тоді, коли економія або ізоляція перевищують додаткові витрати на платформу.
Безпека й дотримання вимог: єдиний застосунок дає змогу централізувати засоби контролю та скоротити кількість облікових записів, секретів, кінцевих точок і цілей для оновлень, проте широкий внутрішній доступ збільшує масштаб можливих наслідків. Сервіси можуть забезпечити сильну ізоляцію й окремі межі аудиту, але кожен інтерфейс, обліковий запис робочого навантаження, копія даних, ланцюжок розгортання та середовище виконання стають новими об’єктами контролю. Оцінюйте обсяг доказів і роботу з реагування, а не лише поділ на схемі.
Вартість: ураховуйте витрати часу людей і навантаження на знання команди, а не тільки обчислювальні ресурси. Кожен сервіс додає сховища коду або модулі, ланцюжки розгортання, облікові записи, панелі показників, сповіщення, оновлення, контракти, знання для чергувань і роботу протягом усього життєвого циклу. Зміни: порівнюйте час від постановки завдання до випуску, частоту розгортань, частку невдалих змін, швидкість відновлення та очікування між командами. Відповідальність: сервіс без постійної команди стає бездоглядним; моноліт без закріпленої відповідальності за модулі перетворюється на спільний ресурс, за який не відповідає ніхто. Архітектура має робити відповідальність зрозумілішою, а не просто переносити її.
Обирайте за обмеженнями, а не за архітектурною модою
Віддавайте перевагу моноліту або модульному моноліту, коли продукт і предметна область ще змінюються, одна чи кілька команд тісно співпрацюють, більшість частин системи має спільні цільові показники роботи, часто потрібна сувора узгодженість даних, а швидке навчання важливіше за незалежний випуск. Якомога раніше встановіть межі модулів, архітектурні перевірки, чітку відповідальність за дані, спостережуваність, автоматизований випуск і відповідальність за роботу в промисловому середовищі. Ці правила корисні вже зараз і зберігають можливість виділити сервіси в майбутньому.
Розглядайте мікросервіси, коли факти свідчать про сталі межі предметної області та регулярну потребу в незалежності. Ознаками можуть бути постійні конфлікти під час випусків між самостійними командами, істотно різні профілі навантаження, потреба в ізоляції через ризики або регуляторні вимоги, різні цілі доступності й відновлення чи окрема бізнес-функція, якій корисні власний життєвий цикл або технологія. Переконайтеся, що за кожен сервіс відповідатиме конкретна команда — разом з інцидентами, залежностями, витратами, оновленнями та виведенням з експлуатації.
Перевірте готовність організації: надійний CI/CD, автоматизацію інфраструктури, керування секретами й обліковими даними, перевірку контрактів, централізовану телеметрію з розподіленим відстеженням, каталог сервісів, порядок керування інцидентами, планування потужності, реагування на загрози та підтримку платформи. Це постійні компетенції, а не одноразовий проєкт налаштування. Використовуйте запис рішення зі зваженими критеріями: спостережуваними обмеженнями, варіантами, наслідками, припущеннями й умовою перегляду. «Колись ми, можливо, виростемо» — припущення; виміряне вичерпання ресурсів або тривале блокування команд — доказ.
Обирайте варіант, помилки в якому дешевше виправити. Внутрішні межі згодом можуть стати мережевими, тоді як передчасне виділення сервісів часто прив’язує команди до контрактів і роботи із супроводу ще до належного розуміння предметної області. Зафіксуйте факти, які змінять рішення: зростання команд, очікування випусків, виміряне вичерпання ресурсів, вимоги до ізоляції, історію збоїв або збільшення рутинної роботи з платформою. Архітектура — це керована гіпотеза, а не незмінна характеристика системи.
Виділяйте сервіс лише тоді, коли користь від поділу виправдовує витрати
Не починайте міграцію з бажаної кількості сервісів. Почніть із вимірюваного обмеження та ділянки системи, яку можна виділити. Спочатку зробіть цю межу помітною всередині моноліту: призначте відповідального, звузьте інтерфейс, усуньте циклічні залежності, припиніть неконтрольований доступ до бази даних, додайте тести, що фіксують поточну поведінку, і перевірки контрактів, а потім виміряйте, як часто ця частина змінюється і як поводиться під навантаженням. Розподілення посилює нечітку межу, а не виправляє її.
Оберіть частину системи, що цілісно відповідає за окрему бізнес-функцію, обмеженою транзакційною зв’язаністю, зрозумілим контрактом для споживачів і конкретною користю — незалежним масштабуванням, ізоляцією, випуском або відповідальністю. До виділення визначте ознаки успіху: коротший час від завдання до випуску, менший масштаб наслідків збою, нижчу вартість ресурсів, окремі цільові показники сервісу, менше очікування між командами або зрозуміліший розподіл відповідальності під час інцидентів. Не обирайте центральний реєстр операцій, контур ідентифікації чи тісно пов’язану оркестрацію як першу пробу, якщо межа та її модель узгодженості ще не вивчені.
Замінюйте систему поступово. Спрямуйте контрольовану частину запитів до нового сервісу, закріпіть за ним виключну відповідальність за дані, опублікуйте сумісні контракти або події, звіряйте стан, спостерігайте за обома шляхами та зберігайте перевірений запасний варіант, доки не з’явиться достатня впевненість. Спроєктуйте обмеження часу очікування, ідемпотентність, повторні спроби, оброблення дублікатів, порядок повідомлень, керування вхідним потоком, автентифікацію, трасування, сповіщення, інструкції для експлуатації та повернення до попередньої версії ще до того, як від них залежатиме робочий трафік. Не залишайте постійний прямий доступ до старої бази даних як прихований спосіб інтеграції.
Плануйте співіснування як повноцінний робочий стан. Визначте, яка система є джерелом істини для кожного факту, куди надходять записи, як переносяться історичні дані, як виявляють і виправляють розбіжності та як фахівці підтримки знаходять відповідальний складник. Установіть строк і відповідального для тимчасових шляхів синхронізації. Паралельний запис без механізму звіряння перетворює рідкісні порушення послідовності в часі на непомітну втрату даних.
Після кожного виділення порівнюйте користь із новим навантаженням на супровід. Зупиніться, якщо наступна межа не виправдовує витрат. Гібридна архітектура цілком нормальна: модульне ядро може співіснувати з кількома незалежними сервісами та керованими зовнішніми службами. Мета полягає не в завершенні красивої історії міграції, а в усуненні конкретних обмежень зі збереженням можливості надійно вносити зміни.
Найкраща архітектура — це найменший набір меж, який дає реальним командам змінювати, масштабувати, ізолювати, розуміти й відновлювати продукт із потрібними швидкістю та рівнем ризику. Кожна додаткова межа має протягом усього свого існування виправдовувати постійні витрати на узгодження й супровід.— GARNO.TECH
Проєктуйте мінімальну архітектуру, достатню за наявними фактами
Архітектурна порада має завершуватися зміною, яку можна впровадити й підтримувати, а не схемою. Під час оцінювання слід відобразити ключові сценарії користувачів, відповідальність за предметні області й дані, структуру команд, залежності під час розгортання, цільові показники сервісів, інциденти, потужність, межі безпеки, хмарні витрати та зміни, які зараз чекають на узгодження. Важливо відрізнити проблему будови коду від проблеми розгортання, бази даних, платформи або організації.
GARNO.TECH допомагає командам проєктувати нові системи, ділити на модулі наявні застосунки й виділяти сервіси, коли такий крок підтверджений фактами. Робота може охоплювати визначення предметних областей, архітектурні рішення, аналіз залежностей, контракти API й подій, розділення даних, інфраструктуру та CI/CD, спостережуваність, стійкість, послідовність міграції, критерії прийняття й передавання знань внутрішнім командам.
Корисне оцінювання дає запис рішення та послідовність дій, а не кошторис повного переписування. Воно визначає першу межу або внутрішнє поліпшення, вимірювані критерії прийняття, залежності, відповідального за експлуатацію, план повернення чи співіснування та вихідні показники для оцінювання користі. Воно також показує роботу, яку сама архітектура не виконає: нечітку відповідальність за продукт, перевантажені команди, відсутні практики якості, ненадійні дані або стимули, що винагороджують початок, а не завершення.
Рекомендованим результатом може стати сильніший модульний моноліт, гібридна система або сервісна архітектура. Найпростіший обґрунтований варіант усуває головне обмеження сьогодення, дає змогу безпечно внести наступну зміну та спирається на команду, готову його експлуатувати. Перегляньте рішення, коли межі предметної області, структура команд, дані про навантаження або цільові показники сервісів істотно зміняться.
Наші дослідження
Дослідження та розробка рішень на основі штучного інтелекту для оптимізації бізнес-процесів і підвищення ефективності прийняття рішень.
Аналіз моделей машинного навчання для прогнозної аналітики у фінансовій сфері, електронній комерції та SaaS-платформах.
Дослідження технологій обробки природної мови та комп'ютерного зору для посилення автоматизації, персоналізації та підтримки клієнтів.


