Пошук уроків, статей та іншого контенту
Визначаємо вимоги, компроміси, ризики та ознаки, за якими обирають або відкидають архітектурний підхід.
Архітектурний патерн описує загальний спосіб побудови системи. Наприклад:
моноліт;
модульний моноліт;
мікросервісна архітектура;
подієва архітектура;
клієнт-серверна архітектура.
Не існує патерна, який був би найкращим для всіх проєктів. Кожен підхід допомагає вирішити одні проблеми, але створює інші.
Наприклад, мікросервіси можуть спростити незалежне масштабування частин системи, але водночас додають:
мережеву взаємодію;
складніше розгортання;
моніторинг багатьох компонентів;
ризики проблем із узгодженістю даних;
вищі вимоги до команди.
Тому вибір архітектури — це не пошук «найсучаснішого» рішення. Це пошук підходу, який найкраще відповідає конкретним вимогам і обмеженням.
Перед вибором патерна потрібно зрозуміти, що саме система має робити і в яких умовах працювати.
Функціональні вимоги описують можливості системи:
користувач може створити замовлення;
адміністратор може змінити ціну товару;
система надсилає сповіщення;
оператор може сформувати звіт.
Ці вимоги визначають поведінку системи, але не завжди безпосередньо визначають архітектуру.
Нефункціональні вимоги описують властивості системи:
кількість запитів за секунду;
допустимий час відповіді;
доступність;
безпека;
узгодженість даних;
можливість масштабування;
час відновлення після збою;
складність експлуатації.
Саме вони часто найбільше впливають на вибір архітектурного підходу.
Наприклад:
Система повинна обробляти 100 запитів на секунду, а відповідь має надходити не пізніше ніж за 300 мілісекунд.
Це конкретніше, ніж вимога «система має бути швидкою».
Потрібно оцінити:
скільки буде користувачів;
скільки запитів очікується;
чи буде навантаження стабільним;
які частини системи можуть зростати швидше за інші.
Для невеликого внутрішнього сервісу простий моноліт часто є достатнім. Якщо окремі частини системи мають дуже різне навантаження, може знадобитися їх незалежне масштабування.
Важливо не плутати потенційну можливість масштабування з реальною потребою в ній. Архітектура не повинна ускладнюватися лише через припущення про далеке майбутнє.
Потрібно визначити, наскільки швидко різні частини системи повинні бачити зміни.
Сильна узгодженість означає, що після успішної операції всі наступні читання бачать її результат. Це важливо, наприклад, для:
платежів;
залишків на рахунку;
резервування товару;
обліку кількості місць.
У деяких сценаріях допустима eventual consistency — дані можуть стати узгодженими через короткий час. Це може підходити для:
лічильників переглядів;
рекомендацій;
пошукового індексу;
надсилання сповіщень.
Якщо система вимагає складних транзакцій між багатьма частинами, розподілена архітектура може суттєво ускладнити реалізацію.
Варто з’ясувати, які частини системи змінюються разом, а які — незалежно.
Якщо команда часто змінює кілька функцій в одному сценарії, надмірний поділ на окремі сервіси створить зайву взаємодію.
Якщо різні частини:
мають окремі команди;
випускаються з різною швидкістю;
мають різні технологічні або навантажувальні вимоги,
тоді ізоляція компонентів може бути виправданою.
Потрібно оцінити, хто буде:
розгортати систему;
оновлювати компоненти;
налаштовувати моніторинг;
аналізувати помилки;
відновлювати систему після збоїв.
Одна програма і одна база даних зазвичай простіші в експлуатації, ніж багато незалежних сервісів, черг і сховищ.
Архітектурний підхід повинен відповідати не лише можливостям розробників, а й можливостям команди, яка підтримуватиме систему після запуску.
Враховуйте:
розмір команди;
досвід із розподіленими системами;
доступність DevOps або SRE-фахівців;
досвід роботи з хмарною інфраструктурою;
здатність підтримувати обрані інструменти.
Складна архітектура без відповідного досвіду може збільшити кількість помилок і час розробки.
Потрібно врахувати не тільки вартість розробки, а й вартість:
інфраструктури;
моніторингу;
резервного копіювання;
підтримки;
навчання команди;
виправлення збоїв.
Якщо продукт потрібно швидко перевірити на ринку, простіший підхід може бути кращим. Після підтвердження попиту архітектуру можна змінювати поступово.
Моноліт — це система, розгорнута як один застосунок.
Переваги:
простий запуск;
одна точка розгортання;
зручні транзакції в одній базі;
менше мережевих помилок;
нижчі операційні витрати.
Недоліки:
складніше незалежно масштабувати частини;
помилка в одному компоненті може вплинути на весь застосунок;
велика кодова база може стати важкою для змін.
Моноліт часто є розумним вибором для нового продукту, невеликої команди або системи з помірним навантаженням.
Модульний моноліт залишається одним застосунком, але його код розділений на чіткі модулі з визначеними межами.
Переваги:
простіше розгортання, ніж у мікросервісів;
можна ізолювати відповідальність модулів;
зручніше розвивати кодову базу;
легше перейти до розподіленої архітектури за реальної потреби.
Недоліки:
модулі все ще працюють у спільному процесі;
помилки меж між модулями можуть накопичуватися;
незалежне масштабування модулів обмежене.
Це часто компроміс між простотою моноліту та потребою в структурованій системі.
Мікросервіси поділяють систему на окремі сервіси, які можуть розгортатися незалежно.
Переваги:
незалежне масштабування;
ізоляція частин системи;
незалежні цикли розгортання;
можливість використовувати різні технології для різних сервісів.
Недоліки:
мережеві затримки й помилки;
складніша робота з транзакціями;
більше інфраструктури;
складніше тестування;
необхідність централізованого спостереження за системою.
Мікросервіси варто обирати через конкретні потреби, а не лише через бажання мати «сучасну» архітектуру.
Запишіть вимоги у вимірюваній формі:
до 10 000 активних користувачів;
час відповіді для 95% запитів — до 500 мілісекунд;
дані про оплату не повинні втрачатися;
реліз потрібен через шість тижнів;
систему підтримуватимуть троє розробників.
Обмеження можуть бути такими:
обмежений бюджет;
наявна база даних;
вимоги законодавства;
фіксована хмарна платформа;
відсутність команди для цілодобової підтримки.
Обмеження можуть відкинути деякі варіанти ще до детального порівняння.
Не потрібно порівнювати всі архітектури. Достатньо вибрати кілька реалістичних варіантів, наприклад:
простий моноліт;
модульний моноліт;
мікросервіси.
Для початкової оцінки можна використовувати шкалу від 1 до 5:
1 — підхід погано відповідає критерію;
5 — підхід добре відповідає критерію.
Критеріям можна надати вагу. Наприклад, короткий час запуску може бути важливішим за незалежне масштабування.
const criteria = [
{ name: "Швидкість запуску", weight: 5 },
{ name: "Простота експлуатації", weight: 4 },
{ name: "Незалежне масштабування", weight: 2 },
{ name: "Підтримка узгоджених транзакцій", weight: 5 },
{ name: "Відповідність досвіду команди", weight: 4 }
];
const options = {
"Моноліт": [5, 5, 2, 5, 5],
"Модульний моноліт": [4, 4, 3, 5, 4],
"Мікросервіси": [2, 1, 5, 2, 2]
};
for (const [optionName, ratings] of Object.entries(options)) {
const score = ratings.reduce((total, rating, index) => {
return total + rating * criteria[index].weight;
}, 0);
console.log(`${optionName}: ${score} балів`);
}Таке оцінювання не замінює інженерний аналіз. Воно допомагає зробити припущення явними та пояснити, чому один варіант кращий за інший.
Для кожного кандидата запитайте:
що станеться при зростанні навантаження;
що станеться при відмові компонента;
наскільки складно буде відновити систему;
де можуть виникнути проблеми з даними;
чи зможе команда підтримувати рішення.
Не всі ризики потрібно усувати одразу. Але їх потрібно бачити до ухвалення рішення.
Корисно коротко записати:
яку архітектуру обрано;
які вимоги вплинули на рішення;
які альтернативи розглядалися;
які недоліки прийнято;
за яких умов рішення потрібно переглянути.
Наприклад:
Обираємо модульний моноліт, оскільки продукт має короткий строк запуску, невелику команду та потребує узгоджених транзакцій. Перехід до окремих сервісів розглядатимемо, якщо окремий модуль почне вимагати незалежного масштабування або незалежного циклу релізів.
Архітектурний варіант слід відкинути, якщо:
він порушує критичну вимогу;
команда не може його надійно підтримувати;
вартість експлуатації не відповідає бюджету;
він додає складність без потрібної користі;
він створює неприйнятний ризик для даних або доступності;
його переваги стосуються лише гіпотетичних майбутніх проблем.
Якщо підхід не відповідає хоча б одній обов’язковій вимозі, високий загальний бал не робить його придатним.
Популярність технології не доводить, що вона підходить конкретному проєкту.
Потрібно запитувати не «що зараз використовують усі?», а:
Яку проблему цей підхід вирішує в нашій системі?
Мікросервіси не є автоматичним способом зробити систему масштабованою або надійною. Без відповідної інфраструктури вони можуть лише збільшити кількість точок відмови.
Архітектура може добре виглядати на діаграмі, але бути надто складною для розгортання, моніторингу й відновлення.
Оцінюйте повний життєвий цикл системи, а не лише написання коду.
Фрази «система має бути дуже швидкою» або «вона точно виросте» не дають достатньо інформації для вибору.
Замінюйте їх конкретними оцінками та перевіряйте ці оцінки навантажувальними тестами або прототипом.
Неможливо точно передбачити розвиток продукту. Краще обрати просту архітектуру з чіткими межами й можливістю еволюції, ніж одразу будувати складну систему для всіх можливих сценаріїв.
Архітектурний патерн обирають відповідно до вимог, а не за популярністю.
Найважливіші критерії — масштаб, узгодженість даних, незалежність змін, складність експлуатації, можливості команди, строки та бюджет.
Моноліт зазвичай простіший у запуску й підтримці.
Модульний моноліт допомагає зберегти простоту та водночас встановити межі між частинами системи.
Мікросервіси виправдані конкретною потребою в незалежному масштабуванні, розгортанні або командній автономності.
Під час вибору потрібно явно зафіксувати компроміси та найбільші ризики.
Простішу архітектуру варто обирати за замовчуванням, якщо складніший підхід не дає необхідної переваги.