Як спроєктувати перший мікросервіс: поради та помилки | robot_dreams
Для отслеживания статуса заказа — авторизируйтесь
Введите код, который был выслан на почту Введите код с SMS, который был выслан на номер
 
Код действителен в течение 5 минут Код с sms действителен в течение 5 минут
Вы уверены, что хотите выйти?
Сеанс завершен
На главную
Як спроєктувати перший мікросервіс і не зламати систему

Як спроєктувати перший мікросервіс і не зламати систему

Про помилки, які роблять майже всі, — і як їх уникнути

Перший мікросервіс майже ніколи не ламає систему одразу. Натомість це відбувається поступово — через ускладнені деплої, приховані залежності, дивні баги в продакшені та відчуття, що «архітектура стала складнішою, а користі менше».

Проблема не в тому, що мікросервісна архітектура погана, а в тому, що це архітектурна точка неповернення. Саме мікросервісна архітектура задає підхід до кордонів, контрактів, даних, тестування і відповідальності. Якщо на цьому кроці ухвалити погані рішення, кожен наступний сервіс лише масштабуватиме ці помилки.

Раніше ми вже розповідали, в чому суть мікросервісної архітектури. Тож у цій статті говоримо не про те, як «переписати систему на мікросервіси», а як зробити перший крок так, щоб система залишилася стабільною. 

Розглянемо сценарії, коли взагалі не варто починати з мікросервісів, як обрати правильний перший сервіс та які рішення критично важливо продумати ще до першого деплою.

Коли не варто починати з мікросервісів

Мікросервіси часто подаються як «наступний логічний крок» після монолітної архітектури. Але на практиці погано обраний момент переходу ламає більше систем, ніж погано обраний дизайн.

Перш ніж вирізати перший сервіс, важливо розуміти, чи готова до цього система і команда. Як це визначити?

Є кілька сигналів, які майже завжди означають, що з мікросервісами варто зачекати.

  • Ви не можете стабільно деплоїти навіть моноліт

Якщо для вас кожен реліз передбачає ручні кроки, нічні деплої, та страх щось зламати, мікросервіси лише масштабуватимуть цей хаос. Окремий сервіс не спростить деплой — він просто додасть ще один.

  • У вас немає чітких меж у поточній системі

Якщо складно відповісти, де закінчується одна бізнес-відповідальність і починається інша, який модуль «володіє» якими даними, то винесення сервісу буде випадковим. А логічно, що випадкові кордони — найгірші кордони.

  • Команда не має досвіду підтримки продакшену

Мікросервіси — це не лише код. Вони також включають алерти, інциденти, деградації.  Якщо команда ще не звикла жити з цим у межах одного застосунку, кілька сервісів ситуацію не покращать.

  • Система ще активно змінюється концептуально.

Коли бізнес-логіка постійно переосмислюється, флоу ламаються щомісяця, а вимоги нестабільні — жорсткі сервісні межі починають заважати, а не допомагати.

Типова помилка: мікросервіси, «бо так модно»

Одна з найпоширеніших причин появи першого мікросервісу залежить від трендів. Щойно бізнеси почали адаптувати цю модель, інші вирішили: «Якщо всі так роблять, значить, нам теж треба».

Мікросервіси не прискорюють розробку автоматично, не роблять систему «більш масштабованою» самі по собі й точно не зменшують складність. Вони лише переносять складність з коду в архітектуру та операції. В результаті команда отримує систему, яку складніше змінювати, ніж попередній моноліт, — і при цьому без відчутних вигод.

Як правильно обрати перший мікросервіс

Після того як рішення рухатися в бік мікросервісів уже ухвалено, виникає найважливіше питання: з чого почати.

Який функціонал підходить для винесення

Хороший кандидат на перший мікросервіс має кілька характерних ознак.

  • Чітка бізнес-відповідальність. Функціонал має легко описуватись одним реченням. Він «відповідає за…», «володіє процесом…», «керує станом…». Якщо для пояснення сервісу потрібна діаграма з десяти стрілок — це поганий знак.
  • Мінімальна кількість залежностей. Ідеально, якщо сервіс рідко викликає інші частини системи, не потребує синхронної координації з core-логікою, та може працювати з деградацією.
  • Асинхронна взаємодія можлива або природна. Це функціонал, який може реагувати на події, працювати з eventual consistency та краще переживає початкові помилки дизайну.
  • Відчутна, але не критична цінність. Перший сервіс має давати користь бізнесу, але не бути точкою, падіння якої зупиняє всю систему.

З іншого боку, деякі частини системи майже гарантовано стануть поганим першим мікросервісом.

До таких можна віднести core-домен і критичні бізнес-флоу. Сюди входять платежі, білінг, авторизація, основні транзакції. Всі ці речі потребують сильної консистентності та мають високі SLA.

Також не варто адаптувати під мікросервісну архітектуру функціонал, який обʼєднує різні модулі. Цей функціонал агрегує дані з багатьох частин системи, координує складні процеси та майже завжди стає вузлом залежностей. Виносячи його першим, ви лише переносите моноліт у мережу.

Принцип low risk / high value

Продовжуючи тему хороших кандидатів на перший мікросервіс, є принцип low risk / high value який допомагає обрати той самий функціонал, який годиться під перший мікросервіс. 

Під low risk мається на увазі, що:

  • Падіння сервісу не зупиняє систему
  • Його можна відключити або обійти
  • Наслідки помилок контрольовані

High value ж означає, що:

  • Команда отримує реальний досвід роботи з контрактами, деплоями, моніторингом, інцидентами
  • Сервіс живе в продакшені, а не в ізоляції

Приклади вдалих і невдалих кандидатів

Не всі частини системи однаково підходять для першого мікросервісу. Різниця між вдалим і невдалим вибором зазвичай не в складності коду, а в характері відповідальності та ризику.

Хорошими першими мікросервісами часто стають:

  • Сервіси нотифікацій (email, push, webhooks)
  • Генерація звітів або аналітики
  • Обробка файлів або медіа
  • Рекомендації або підбір контенту
  • Фонові процеси, які не блокують основні флоу.

Такі сервіси зазвичай мають чітку й зрозумілу відповідальність, добре працюють асинхронно та легко деградують без зупинки всієї системи.

Натомість поганими кандидатами для першого кроку часто виявляються:

  • Авторизація та автентифікація
  • Білінг та платежі
  • Основні CRUD-флоу продукту
  • Сервіси, що «знають про всіх» і все координують.

Вони швидко стають джерелом складних та крихких dependency між сервісами, проблем із консистентністю даних та навіть страху будь-яких змін і деплоїв.

Межі сервісу: що входить, а що — ні

Після вибору першого мікросервісу важливо розуміти, де саме провести межу. Помилка на цьому етапі рідко ламає систему одразу, але майже завжди призводить до поступового повернення до розподіленого моноліту.

Один сервіс = одна відповідальність

Технічно це означає, що сервіс має один основний тип state, за який відповідає. Сервіс змінюється з однієї домінівної причини та не ухвалює рішень, які належать іншому домену.

Так, якщо в коді сервісу з’являються conditional-гілки, що залежать від зовнішніх сервісів, та/або логіка, яка «знає», як працює інший домен, — це ознака розмитої межі.

Для першого сервісу не потрібна повна доменна модель. Достатньо відповісти на кілька технічних запитань:

  • Якими запитами цей сервіс користується?
  • Які події він продукує або споживає?
  • Який state він зберігає та оновлює самостійно?
  • Що станеться, якщо сервіс стане тимчасово недоступним?

Хороша початкова межа для мікросервісу зазвичай має мінімальну кількість API-ендпоінтів, обмежений набір input/output DTO та не має знань про внутрішню структуру інших сервісів.

Дані та консистентність

З появою першого мікросервісу дані більше не живуть в одному транзакційному контексті. На цьому етапі ламається найбільше припущень, які добре працювали в монолітній структурі

Чому «просто транзакції» більше не працюють

У моноліті звична модель виглядає просто, в неї є одна база, одна транзакція. Так, при змінах або зберігається все, або нічого. Після появи окремого сервісу ця модель перестає існувати. Запис у дві бази — це вже розподілена транзакція, а вони складніші в реалізації, погано масштабуються і важкі в підтримці та дебагу.

Як уникнути data inconsistency на першому кроці

Повної консистентності в розподіленій системі не існує, і це важливо прийняти одразу.

Завдання першого мікросервісу — зробити неконсистентність контрольованою. На старті є декілька підходів, які допоможуть:

1. Чітке володіння даними. Кожен сервіс є єдиним джерелом істини для своїх даних і не дозволяє іншим сервісам змінювати свій state напряму.

2. Асинхронне поширення змін. Замість синхронного оновлення кількох систем сервіс зберігає свій стан, публікує подію про зміну, а інші сервіси реагують на неї у своєму темпі.

3. Ідемпотентність операцій. В розподіленій системі повідомлення можуть приходити двічі, а retries — це норма. Операції мають бути спроєктовані так, щоби повторне виконання не ламало дані.

Обробка помилок та відмов

В силу їхньої архітектури в мікросервісах не буває так, що застосунок упав — і ціла система не працює. Натомість система може «працювати», але неправильно.

Саме тому обробка відмов стає надважливою.

Що буде, якщо сервіс впаде

У песимістичному сценарії, сервіс може бути недоступним кілька секунд, повільно відповідати й повертати помилки. Кожен клієнт цього сервісу має чітко розуміти, що робити в такому випадку, чи можна продовжити роботу та які дані вважати валідними. Для таких випадків є 3 механізми: retries, timeouts і graceful degradation.

  • Timeouts. Виклик без тайм-ауту швидко породжує зависання.Тайм-аут має бути коротшим, ніж очікуваний SLA, відрізнятися для різних типів запитів та вважатися нормальним сценарієм, а не винятком.
  • Retries. Повторні спроби корисні, але небезпечні. Без обмежень вони множать навантаження, а без backoff — створюють «шторм»» запитів. Так, вони мають бути обмеженими за кількістю і мати експоненційну затримку.
  • Graceful degradation. Не кожна помилка має зупиняти флоу. Часто найкраща поведінка передбачає часткову відповідь, fallback-логіку та дозвіл для некритичних кроків. Зрештою, сервіс, який вміє деградувати, робить систему стійкішою, навіть якщо працює неідеально.

Найгірший сценарій в мікросервісах — каскадна відмова, коли проблема в одному сервісі «прокочується» по всій системі. Щоб цього уникнути, важливо дотримуватись кількох принципів:

  • Не будувати довгі синхронні ланцюжки викликів
  • Ізолювати критичні флоу від некритичних
  • Чітко розрізняти бізнес-помилки й технічні збої
  • Вважати відмову нормою, а не винятком

На завершення

Тема мікросервісної архітектури майже невичерпна. Завдяки її гнучкості й адаптивності тут завжди є про що поговорити, і список нюансів може бути нескінченним. Описати все що тільки можна в одній статті — неможливо. Втім, сподіваємось, цей огляд стане вам у пригоді при знайомстві з мікросервісами.

Все ж для вивчення теми однієї статті замало. Курс з мікросервісної архітектури від robot_dreams стане куди кращим гайдом та порадником у цій сфері. На курсі студенти разом із Михайлом Єдемським вивчають усе: від моделювання мікросервісів та стратегії — до масштабування, тестування та розгортання. 

Ещё статьи
Порівнюємо швидкість, якість і відповідальність за результат