Мікросервіси
Мікросервіси — це архітектура, у якій одну систему будують як набір невеликих сервісів: кожен деплоїться окремо, володіє власними даними й належить одній команді. Незалежний деплой — те, що цей стиль купує, а кожен виклик, який тепер іде через мережу, — те, чим за це платять. Сторінка починається з шістнадцяти проблем, які додає мережа, і патерну, що відповідає на кожну; далі — дев’ять характеристик, якими цей термін визначили, що потрібно мати до другого сервісу, дані між сервісами, виклики між сервісами, експлуатація багатьох сервісів, п’ять задокументованих збоїв і де все це вироджується.
- Визначальна риса
- Деплоїться окремо, володіє своїми даними
- У масштабі
- Uber, 2020: ~2200 сервісів, перегрупованих у 70 доменів
- Режим відмови
- Розподілений моноліт; шторми повторів
Що додає мережа — шістнадцять проблем, патерн для кожної і його ціна
Усередині одного процесу виклик — це виклик функції. Він триває наносекунди й або повертає результат, або кидає виняток. Дані живуть в одній базі, тож одна транзакція тримає дві таблиці узгодженими. Поділ системи на сервіси перетворює кожен такий виклик на мережевий, а кожну спільну таблицю — на чужі дані. Кожна така зміна створює проблему, якої моноліт не мав. Для кожної з цих проблем є відомий патерн, і кожен патерн має ціну. Ось шістнадцять таких проблем і момент, коли потрібна відповідь на кожну. Наступні розділи посилаються на рядки за номерами.
| # | Проблема | Патерн | Чого коштує | Потрібно з |
|---|---|---|---|---|
| 1 | Виклик зависає, і потоки викликача накопичуються в очікуванні | Таймаут на кожному виклику, заданий від затримки викликаного; дедлайн, переданий далі вниз | Повільний, але справний виклик обривається, тож кожному таймауту потрібна запланована відповідь | Першого сервісу |
| 2 | Виклик падає один раз — перезапущений екземпляр, загублений пакет | Повтор з експоненційною затримкою та джитером — лише на одному рівні | Додаткове навантаження саме тоді, коли викликаному важко; три спроби на кожному з п’яти рівнів — це 243 виклики | Першого сервісу |
| 3 | Залежність лежить, а кожен викликач і далі її довбе | Бюджет повторів або запобіжник (circuit breaker), що на час припиняє виклики | Запобіжник — це другий режим поведінки, який треба тестувати, і він може сповільнити відновлення | Коли багато викликачів ділять одну залежність |
| 4 | Одна повільна залежність забирає всі потоки викликача | Переборка (bulkhead): окремий пул або ліміт паралельності на кожну залежність | Потужність простоює в пулах, які зараз не зайняті | Коли сервіс викликає кілька інших |
| 5 | Повтор повторює дію, яка вже сталася | Ключ ідемпотентності: отримувач пам’ятає, що вже зробив | Стан, який отримувач мусить зберігати й прибирати | Першого виклику, що змінює стан |
| 6 | Запитів приходить більше, ніж сервіс може обслужити | Скидання навантаження й ліміти частоти: відмовляти рано, до виконання роботи | Частина користувачів отримує швидку помилку зараз, а не всі — повільну згодом | Першого піку трафіку |
| 7 | Двом сервісам потрібна та сама таблиця | База на сервіс: один власник, а решта питає через його API | Жодних JOIN між сервісами; звітам потрібна власна копія | Першого сервісу |
| 8 | Одна бізнес-дія охоплює кілька сервісів, а транзакції між ними немає | Сага: ланцюг локальних транзакцій, кожна з компенсаційним кроком | Скасування ви пишете самі, а паралельні саги бачать напівготовий стан одна одної | Першого потоку, що пише у два сервіси |
| 9 | Зберегти рядок і опублікувати подію треба або обидва, або жодне | Transactional outbox: подію записують у тій самій транзакції, а ретранслятор її публікує | Ще один процес-ретранслятор; події приходять щонайменше раз, іноді двічі | Першої події, на яку покладається інший сервіс |
| 10 | Та сама подія приходить двічі або не в тому порядку | Ідемпотентний споживач: записувати id оброблених повідомлень; перевіряти версії | Таблиця оброблених id для кожного споживача | Першого споживача |
| 11 | Одному екрану потрібні дані п’яти сервісів | Композиція API або модель для читання, зібрана з подій (CQRS) | Композиція множить виклики; модель для читання завжди трохи відстає | Першої сторінки, що охоплює кілька сервісів |
| 12 | Екземпляри з’являються й зникають, тож адреси весь час змінюються | Виявлення сервісів: реєстр або DNS від платформи | Реєстр стає тим, від чого залежить кожен виклик | Другого сервісу |
| 13 | Клієнтові довелося б викликати двадцять сервісів | Шлюз API або окремий бекенд для кожного фронтенду (BFF) | Ще один перехід і шлюз, який має звичку обростати бізнес-логікою | Першого клієнта, якому потрібні два сервіси |
| 14 | Кожному сервісу потрібні шифрування, повтори й метрики — у кожній мові | Спільна бібліотека або сервісна сітка (service mesh): проксі поруч із кожним сервісом чи вузлом | Бібліотека прив’язує сервіси до своїх мов; сітка — ще одна розподілена система в експлуатації | Десятків сервісів |
| 15 | Запит упав десь на шляху через вісім сервісів | Розподілене трасування: id трасування передається з кожним викликом, і логи його містять | Інструментування в кожному сервісі та сховище для трас | Другого сервісу |
| 16 | Зміна одного API ламає викликача, про якого ніхто не знав | Зворотно сумісні зміни, версійовані API, контрактні тести від споживачів | Старі версії, які треба підтримувати, і набір контрактів на кожного споживача | Другої команди |
Що робить сервіс мікросервісом — дев’ять характеристик і та одна, що визначає
Забудьте на мить про «мікро». Цей склад завдав більше шкоди, ніж будь-який інший у цій темі, бо запрошує міряти сервіси рядками коду. Важлива властивість — це питання з відповіддю «так» чи «ні». Чи можна змінити, протестувати й задеплоїти цей сервіс у продакшн, не деплоячи нічого іншого? Якщо так — це мікросервіс. Якщо реліз вимагає, щоб два сервіси вийшли разом, у вас один сервіс у двох репозиторіях. Сем Ньюман формулює це одним рядком: мікросервіси — це незалежно деплойовані сервіси, змодельовані навколо бізнес-домену.
Термін визначили 25 березня 2014 року, коли Джеймс Льюїс і Мартін Фаулер описали «підхід до розробки одного застосунку як набору невеликих сервісів, кожен з яких працює у власному процесі й спілкується через легкі механізми». Формального визначення вони не дали. Натомість перелічили дев’ять характеристик, які зазвичай мали спільними системи, що вони бачили. Більшість пояснень цей список пропускає, і дарма, бо кожен пункт називає спосіб, яким стиль ламають на практиці. Ось усі дев’ять у їхньому порядку:
| # | Характеристика | Що це означає | Як виглядає, коли її немає |
|---|---|---|---|
| 1 | Компоненти як сервіси | Компонент — це те, що деплоїться окремо й викликається через мережу, а не бібліотека, вбудована в процес | Сервіси, які мусять виходити разом |
| 2 | Організація навколо бізнес-можливостей | Сервіси й команди йдуть за тим, що робить бізнес: замовлення, ціни, доставка | «Сервіс бази даних», «сервіс валідації», «сервіс API» — шари з мережевими викликами між ними |
| 3 | Продукти, а не проєкти | Одна команда володіє сервісом увесь його вік, зокрема в продакшні, — амазонівське «you build it, you run it» | Проєктна команда будує його, передає експлуатації й іде далі |
| 4 | Розумні кінцеві точки й тупі труби | Логіка живе в сервісах; транспорт — HTTP, простий брокер — лише переносить повідомлення | Корпоративна шина сервісів або шлюз, що маршрутизує за бізнес-правилами |
| 5 | Децентралізоване управління | Кожна команда обирає інструменти під свій сервіс у межах кількох спільних стандартів | Або один обов’язковий стек для всього, або сорок мов, під які нікого не знайти |
| 6 | Децентралізоване керування даними | Кожен сервіс володіє своїми даними й своєю моделлю; «клієнт» може означати різне для двох сервісів | Спільна база даних — визначальна риса розподіленого моноліту |
| 7 | Автоматизація інфраструктури | Тестування, деплой і створення середовищ автоматизовані | Ручний крок деплою, помножений на кількість сервісів |
| 8 | Проєктування з розрахунку на збій | Будь-який виклик може впасти, тож кожен сервіс мусить це витримувати, — і збій перевіряють, а не припускають | Виклики без таймаутів; ніхто ніколи навмисно не вимикав залежність |
| 9 | Еволюційний дизайн | Сервіси можна переписати чи викинути; межі йдуть за тим, що змінюється разом | Сервіси, які ніхто не наважується видалити |
Правило даних старше за саме слово. 2006 року технічний директор Amazon Вернер Фогельс описав сервісно-орієнтовану архітектуру, до якої компанія перейшла після 2001 року, коли її монолітний фронтенд перестав масштабуватися. Кожен сервіс інкапсулював свої дані разом із бізнес-логікою, що з ними працює. «Прямий доступ до бази ззовні сервісу заборонено, — сказав він, — і жодного спільного використання даних між сервісами немає». У тому ж інтерв’ю він дав правилу власності гасло: «You build it, you run it» — «збудував — експлуатуй». Льюїс і Фаулер через вісім років процитували гасло про власність, а їхня шоста характеристика переказує правило даних. Відтоді правила майже не змінилися; змінилося те, скільки існує інструментів, щоб їх дотримуватися.
Що потрібно мати до другого сервісу
28 серпня 2014 року Мартін Фаулер опублікував короткий список того, що потрібно команді, перш ніж будувати мікросервіси, і анонсував його фразою «You must be this tall to use microservices» — як табличка зі зростом біля атракціону. У списку чотири пункти. Жоден не екзотичний, і один застосунок може роками жити без будь-якого з них. Двадцять сервісів без них не протягнуть і тижня. Ось вони — з перевіркою, яку можна провести у своїй команді сьогодні:
| Передумова | Що це означає | Чому двадцять сервісів без неї не можуть | Перевірка на сьогодні |
|---|---|---|---|
| Швидке створення середовищ | Новий сервер чи середовище за години, автоматично, а не після черги тікетів | Якщо новий сервіс дорого підняти, команди чіпляють фічі до наявних, і межі пливуть | Скільки часу від порожнього репозиторію до сервісу, що працює в продакшні? |
| Базовий моніторинг | Технічні збої й бізнес-сигнали швидко видно в продакшні | Коли сервісів багато, збій проявляється далеко від своєї причини | Чи видно просто зараз, скільки замовлень не пройшло за останні п’ять хвилин? |
| Швидкий деплой застосунків | Автоматизований конвеєр до тестового й продакшн-середовища | Ручний крок трапляється вдвадцятеро частіше, і саме він не дає командам випускати окремо | Чи може команда задеплоїти один сервіс, нікого не питаючи? |
| Культура DevOps | Розробка й експлуатація працюють як одне ціле, і команди експлуатують те, що будують | Сервіс, який експлуатує окрема команда, на практиці не деплоїться незалежно, хоч би що казала схема | Кого будять, коли сервіс падає о третій ночі? |
За дев’ять місяців Фаулер назвав ціну, що стоїть за цим списком: мікросервісна премія. Автоматизований деплой, моніторинг, обробка збоїв і узгодженість «з часом» — це робота, якої моноліт не потребує, і вона починається ще до появи будь-якої користі. Тож проста система як мікросервіси менш продуктивна, і лише після певного рівня складності стиль окуповує себе. Висновок у нього був різкий: «навіть не розглядайте мікросервіси, якщо у вас немає системи, надто складної, щоб керувати нею як монолітом». Сторінка про моноліт показує, що спробувати до цієї точки, а сторінка «Моноліт → мікросервіси» — як рухатися, коли ви вже за нею.
Дані між сервісами: без JOIN і без спільних транзакцій
Правило просте: кожен сервіс володіє своїм сховищем, і жоден інший його не торкається (рядок 7). Наслідки цього правила — і є основна робота. Вони дивують тих, хто чекав, що найскладнішим буде деплой. Моноліт давав кілька гарантій безкоштовно, і кожну з них тепер треба збудувати заново — або свідомо від неї відмовитися. Таблиця перелічує, що ви втрачаєте і що зазвичай це замінює.
| Що давала одна база | Що замінює це між сервісами | Підступ |
|---|---|---|
| JOIN | Композиція API або модель для читання, яку живлять події (рядок 11) | Композиція балакуча; модель для читання відстає |
| Транзакція через дві таблиці | Сага з компенсаційними кроками (рядок 8) | Скасування пишете ви; між сагами немає ізоляції |
| Зовнішній ключ | Ідентифікатор плюс перевірка в коді та задача, що шукає «сиріт» | Інший сервіс може видалити те, на що ви посилаєтеся |
| Обмеження унікальності | Одним правилом володіє один сервіс, і його питають до запису | Цей сервіс тепер на критичному шляху |
| Прочитати щойно записане | Наступне читання користувача надсилати власникові або показувати стан «в обробці» | Модель для читання якусь мить показує старе значення |
| Один запит для звіту | Копія в аналітичному сховищі, яку живлять події чи журнал бази | Хвилини чи години відставання та ще один конвеєр |
Саги: транзакція, яку ви пишете самі
Розподілені транзакції існують. У двофазній фіксації (two-phase commit) координатор просить кожного учасника підготуватися, а потім зафіксувати зміни, і бази даних підтримують це десятиліттями. Між сервісами її використовують рідко, з трьох причин. Кожен учасник, зокрема брокер повідомлень, мусить її підтримувати, а багато хто не підтримує. Учасники тримають блокування, поки чекають. А якщо координатор відмовить не в той момент, вони лишаються заблокованими, доки він не повернеться. Тож звична відповідь старша й простіша. Гектор Гарсія-Моліна й Кеннет Салем описали її 1987 року для довгих транзакцій усередині однієї бази й назвали сагою (saga).
Сага — це послідовність локальних транзакцій. Кожна фіксується у своєму сервісі й запускає наступну. Кожен крок, який можна скасувати, має компенсаційний крок, що його скасовує, — не відкат, а нову дію з протилежним бізнес-змістом. Сага замовлення створює замовлення в стані «очікує», резервує товар, списує гроші з картки, потім підтверджує. Якщо банк відхилив оплату, сага йде назад: знімає резерв і позначає замовлення відхиленим. Книжка Кріса Річардсона «Microservices Patterns» дає порядку кроків корисний словник. Спершу йдуть кроки, які можна компенсувати. Потім — опорний крок (pivot), після якого сага рухається лише вперед. Кожен крок після нього треба повторювати, доки він не вдасться.
Координувати кроки можна двома способами. В оркестрації один компонент — сервіс чи рушій робочих процесів — каже кожному учасникові, що робити далі, і знає весь потік. У хореографії весь потік не знає ніхто: кожен сервіс слухає події й реагує на них. Вибір визначає, де видно стан саги і де ховатимуться її баґи.
| Оркестрація | Хореографія | |
|---|---|---|
| Хто знає весь потік | Оркестратор | Ніхто; кожен сервіс знає лише свою реакцію |
| Де видно стан однієї саги | В одному місці | Відновлюється з подій у різних сервісах |
| Додати крок | Змінити оркестратор | Додати підписника й перевірити, що ніхто не покладався на старий порядок |
| Як це псується | Оркестратор вбирає бізнес-логіку, що належить учасникам | Ланцюги подій, за якими ніхто не встежить, іноді по колу |
| Добре для | Довгих потоків із кількома компенсаціями, як-от виконання замовлення | Коротких потоків із двома-трьома учасниками |
Outbox: зберегти й опублікувати як один крок
Кожен крок саги закінчується двома записами: власними даними кроку й повідомленням, що каже наступному сервісу рушати. Саме в цій парі дані тихо зникають (рядок 9). Зберегти замовлення, потім опублікувати «замовлення створено» — і якщо процес помре між цими діями, замовлення існує, а більше ніхто про нього не дізнається. Спершу опублікувати, потім зберегти — і збій лишить подію про замовлення, якого не існує. Два записи у дві системи не є транзакцією, хоч як близько вони стоять у коді.
Transactional outbox прибирає цей розрив. Сервіс записує подію в таблицю outbox у власній базі, у тій самій транзакції, що й саме замовлення. Або фіксуються обидва рядки, або жоден. Окремий ретранслятор потім читає outbox і публікує кожну подію. Він може опитувати таблицю або читати власний журнал змін бази — захоплення змін даних (change data captureпотік змін із журналу базиПотокова передача кожної вставки, зміни й видалення з власного журналу змін бази в інші системи, як це роблять інструменти на кшталт Debezium. Вона тримає другу копію синхронною без того, щоб застосунок писав двічі, ціною прив’язки кожного споживача до структури таблиць джерела.Усі терміни), підхід, який використовують інструменти на кшталт Debezium. Ретранслятор може впасти після публікації й до того, як позначить подію надісланою, тож іноді він опублікує її двічі. Саме тому існує рядок 10: кожен споживач записує id оброблених подій і ігнорує повтор.
Усе це успадковує узгодженість «з часом» як продуктове питання, а не технічне. Якщо товар зарезервовано за секунду до підтвердження оплати, хтось має вирішити, що бачить клієнт у цю секунду і що буде, якщо оплата потім не пройде. Це рішення належить бізнесу. Його треба ухвалювати явно для кожного потоку, що перетинає сервіси, а вдавання, що його немає, — це те, як системи починають списувати з людей двічі.
Виклики між сервісами: таймаути, повтори й рахунок за доступність
Кожен виклик між сервісами може бути повільним, може впасти або — найгірше з трьох — може вдатися на тому боці, повернувши вам помилку. Синхронний виклик ще й зв’язує доступність. Припустімо, запит проходить через шлюз, далі замовлення, далі білінг, далі реєстр. Якщо кожен доступний 99,9% часу — це близько 43 хвилин простою на місяць, — то ланцюг доступний 99,6%, тобто майже три години на місяць. Це гірше за будь-який компонент у ньому й гірше за моноліт, що робив ту саму роботу в одному процесі.
Асинхронне ребро розриває цей зв’язок. Якщо оформлення замовлення публікує подію, а пошук її споживає, пошук може лежати годину, і жоден клієнт не помітить цього під час оформлення; пошук наздожене, коли повернеться. Ціна — пошук цю годину показує застарілі результати, і хтось має бути з цим згоден. Ось компроміс одним реченням: синхронні виклики купують свіжість і платять доступністю, асинхронні — купують доступність і платять застарілістю.
Почніть із таймауту (рядок 1), бо без нього не працює ніщо інше: викликач без таймауту тримає потік, доки залежність не відповість, а мертва залежність не відповідає ніколи. Практика Amazon, як її описує Марк Брукер, — обрати прийнятну частку хибних таймаутів, скажімо 0,1%, і поставити таймаут на відповідному перцентилі затримки викликаного — у цьому випадку на 99,9-му. Передавайте залишок часу далі вниз як дедлайн. Інакше сервіс за п’ять переходів униз і далі працює для викликача, який давно здався.
Повтори (рядок 2) — місце, де добрі наміри перетворюються на аварії. Повтор допомагає зі збоєм, що не повториться, як-от перезапущений екземпляр. Проти перевантаженого сервісу він додає навантаження саме тоді, коли навантаження і є проблемою. Повтори ще й множаться. Приклад Брукера — запит, що проходить стеком із п’яти сервісів, із трьома спробами на кожному рівні. Якщо база внизу почне падати під навантаженням, вона отримає 3 × 3 × 3 × 3 × 3 = 243 запити на кожен запит клієнта. Правило Amazon — повторювати лише в одній точці стеку, з експоненційною затримкою (backoffдедалі довша пауза між повторамиПауза перед повтором невдалого виклику, що зростає після кожного збою, — наприклад, 1, 2, 4 і 8 секунд, — зазвичай із випадковою добавкою (jitter), щоб багато клієнтів не повторювали в одну мить. Без неї повтори приходять саме тоді, коли сервіс, якому й так важко, найменше може їх собі дозволити.Усі терміни) та джитером: паузи ростуть і мають випадкову складову, тож клієнти не повторюють у такт.
Обмеження на повтори не дає поганій годині стати поганим днем. Книжка Google про SRE описує два. Кожен запит отримує щонайбільше три спроби. А кожен клієнт стежить, яку частку його запитів становлять повтори, і припиняє повторювати, щойно ця частка сягає 10%. У найгіршому сценарії Google саме перше правило ще дозволяє трафіку вирости майже втричі; обидва разом тримають зростання на рівні приблизно 1,1 раза. Ту саму роботу виконує відро токенів (token bucket) на кожному клієнті, і AWS вбудував його у свої SDKSoftware Development Kit — готовий набір для платформиЗібраний набір бібліотек, інструментів і прикладів для роботи з чужою платформою. Відмінність від API в тому, що API лише описує правила, а SDK дає код, який уже вміє за цими правилами говорити.Усі терміни ще 2016 року.
Запобіжники (рядок 3) — найвідоміша відповідь, і про них сперечаються найбільше. Майкл Найгард назвав запобіжник (circuit breaker) і переборку (bulkhead) у книжці «Release It!» 2007 року. Запобіжник рахує збої і, щойно вони перетинають поріг, на певний час припиняє виклики залежності й натомість швидко повертає помилку. Бібліотека Hystrix від Netflix, відкрита 2012 року, зробила обидва патерни стандартом у світі Java. 19 листопада 2018 року Netflix перевів Hystrix у режим підтримки на версії 1.5.18. Фокус компанії змістився на адаптивні ліміти паралельності, що реагують на виміряну затримку, а не на пороги, задані вручну, і нові проєкти вона скерувала до resilience4j. Amazon у власних настановах іде далі. Запобіжники додають другий режим поведінки, який важко тестувати, пише Брукер, і можуть суттєво подовжити відновлення. Amazon натомість обмежує повтори локальним відром токенів.
| Механізм | Від чого захищає | Чого коштує | Розумне значення на старті |
|---|---|---|---|
| Таймаут | Накопичення потоків за мертвою залежністю | Повільні, але справні виклики обриваються | p99.9 викликаного — для 0,1% хибних таймаутів |
| Передача дедлайну | Роботи для викликача, який уже здався | Кожен перехід мусить його прочитати й передати | Дедлайни gRPC; заголовок у HTTP |
| Повтор із затримкою та джитером | Збоїв, що не повторяться | Додаткове навантаження під час проблем | Три спроби, лише на одному рівні |
| Бюджет повторів | Штормів повторів | Частина запитів падає, хоча повтор їх урятував би | Повтори — менше 10% запитів на клієнта |
| Запобіжник | Викликів залежності, яка явно лежить | Другий режим для тестування; повільніше відновлення | Лише там, де є справжній запасний варіант |
| Переборка | Того, що одна повільна залежність забирає всі потоки | Простій потужності в тихих пулах | Ліміт паралельності на кожну залежність |
| Скидання навантаження | Того, що перевантаження переходить в обвал | Частина користувачів отримує швидку помилку | Відмовляти до будь-якої роботи |
| Ключ ідемпотентності | Дубльованих побічних ефектів від повторів | Отримувач зберігає ключі | На кожному виклику, що змінює стан |
Останній рядок — те, про що ніколи не попереджають джуніорів і на чому обпікся кожен сеньйор (рядок 5). Мережевий збій не каже, чи сталася операція: виклик міг пройти, а загубилася лише відповідь. Тож будь-який повтор будь-чого, що змінює стан, має бути безпечним, а отже, отримувач мусить упізнавати запит, який уже обробив. Клієнт надсилає з запитом унікальний ключ ідемпотентності (idempotency keyid запиту, що робить повтор безпечнимУнікальне значення, яке клієнт надсилає із запитом, що щось змінює, — платежем, замовленням, — щоб сервер упізнав повтор і повернув перший результат, а не діяв двічі. Сервер мусить зберігати ключі й вирішувати, скільки їх тримати; повтор, що прийшов після того, як його ключ прибрали, вважають новим запитом.Докладніше в статті →Усі терміни); отримувач зберігає ключ разом із результатом і на повтор повертає збережений результат. Повтори без ідемпотентності — це не стійкість. Це машина для дублювання побічних ефектів.
Експлуатація багатьох сервісів: трасування, виявлення, шлюзи й сітка
З одним сервісом запит, що впав, лишає один стектрейс. З багатьма — уривки у восьми наборах логів, і нічого їх не з’єднує, якщо ви цього не запланували (рядок 15). Рішення — id трасування, створений на вході й переданий з кожним викликом, щоб кожен рядок логу й кожен замір часу можна було згрупувати за запитом. Переносним це роблять два стандарти. W3C Trace Context, рекомендація W3C з лютого 2020 року, визначає заголовок traceparent, що переносить id між сервісами. OpenTelemetryнезалежний від вендора стандарт телеметріїВідкритий проєкт, що визначає, як застосунки створюють і надсилають траси, метрики й логи, — бібліотеки, формат даних і протокол, — щоб інструмент, який їх зберігає й показує, можна було змінити без повторного інструментування коду. У травні 2026 року він отримав статус graduated у Cloud Native Computing Foundation. Він стандартизує, як збирати телеметрію, а не те, що варто збирати.Усі терміни дає бібліотеки й протокол, щоб збирати траси, метрики й логи без прив’язки до одного постачальника; 11 травня 2026 року проєкт отримав статус graduated у Cloud Native Computing Foundation. Uber описав, чого коштує відсутність трасування: одне розслідування означало пройти близько 50 сервісів дванадцяти команд, щоб знайти першопричину.
Виявлення сервісів (рядок 12) — адресна книга, що дозволяє сервісам знаходити одне одного, поки екземпляри з’являються й зникають. У Kubernetes його дає платформа через DNS; деінде — реєстр на кшталт Consul. Хай там як, це тепер те, від чого залежить кожен виклик, і воно заслуговує на таку саму турботу, як база даних. Roblox засвоїв це за 73 години в жовтні 2021 року — це один із п’яти кейсів нижче.
Шлюз (рядок 13) дає клієнтам одну точку входу замість двадцяти. Його ризик — гравітація: автентифікація, потім правила маршрутизації, потім трохи бізнес-логіки, доки шлюз знову не стане монолітом. Четверта характеристика Льюїса й Фаулера — розумні кінцеві точки, тупі труби — це перевірка, якої слід його тримати. Корисний варіант з’явився в SoundCloud, і 2015 року його описав Сем Ньюман: окремий бекенд для кожного фронтенду, або BFF. Мобільний застосунок і вебсайт отримують кожен тонкий бекенд, яким володіє команда цього клієнта, тож потреби жодного з клієнтів не гнуть спільний API.
Сервісна сітка (рядок 14) виносить із коду в проксі шифрування між сервісами, повтори, таймаути й метрики. Класичні сітки ставлять проксі поруч із кожним сервісом як sidecar; режим ambient в Istio, загальнодоступний із версії 1.24 у листопаді 2024 року, натомість запускає спільний проксі на кожному вузлі. Користь — однаковість для всіх мов. Ціна — друга розподілена система, яку треба експлуатувати й оновлювати, і пастка, яку варто назвати: якщо повторює сітка і повторює застосунок, ви збудували множильний стек із рядка 2, не написавши жодного рядка коду. Вирішіть, який рівень володіє повторами, і вимкніть їх на іншому.
Останній рядок — про зміни (рядок 16). Сервіс незалежний лише тоді, коли його викликачі переживають його релізи. Це означає зміни, що лишаються зворотно сумісними, нову версію, коли інакше не можна, і спосіб узагалі знати, хто вас викликає. Контрактні тести від споживачів роблять останнє перевірюваним: кожен викликач публікує запити, які робить, і поля, які читає, а збірка постачальника падає, коли зміна зламала б когось із них. Версіювання й контракти докладно розібрано на сторінці про проєктування API.
Сервіси й команди, що ними володіють
Мікросервіси — це організаційний дизайн тією ж мірою, що й технічний. Мелвін Конвей 1968 року помітив, що система зрештою віддзеркалює структуру комунікації організації, яка її будує, і цей стиль використовує це свідомо: одна команда, один набір сервісів, одне чергування. Правильний розмір сервісу випливає звідси. Це розмір, який одна команда може зрозуміти, змінювати й експлуатувати, а не кількість рядків. А правильну кількість сервісів обмежує кількість команд, що можуть ними володіти. Таблиця перелічує сигнали, що ці дві речі розійшлися.
| Сигнал | Здоровий стан | Проблема |
|---|---|---|
| Сервісів на команду | Кілька, які команда може обслуговувати на чергуванні | Сервісів більше, ніж людей |
| Скільки сервісів зачіпає типова фіча | Здебільшого один | Три, які випускають синхронно |
| Хто кого викликає | Граф, згенерований із коду чи трас | Зміна ламає викликача, про якого ніхто не знав |
| Чергування | Кожна команда — за свої сервіси | Центральна команда експлуатації — за все |
| Спільний код | Невеликі версійовані бібліотеки | Бібліотека «common», яку кожен сервіс мусить оновити одночасно |
П’ять кейсів і те, чого в кожному бракувало
Кейси на сторінці про моноліт ішли назад — від сервісів до одного процесу. Ці п’ять лишилися із сервісами, і кожен документує ціну з таблиці вгорі цієї сторінки — словами інженерів, які її сплатили.
| Кейс | Що сталося | Що це показує |
|---|---|---|
| Monzo, 2019 | Понад 1500 сервісів і 9300 з’єднань; кожен сервіс міг викликати будь-який інший, доки банк не згенерував список дозволів зі свого коду | Граф викликів існує лише в коді, доки ви його не витягнете (рядок 16) |
| Uber, 2020 | Близько 2200 критичних сервісів перегрупували в 70 доменів за шлюзами | Після певного розміру одиниця, якою проєктують, мусить бути більшою за один сервіс |
| AWS Kinesis, 2020 | Невелике додавання потужності вивело кожен фронтенд-сервер за ліміт потоків; потім залежність «за можливості» заблокувала Cognito | М’яка залежність м’яка лише тоді, коли код, що її викликає, перевірено без неї |
| Roblox, 2021 | 73-годинна відмова кластера Consul, від якого залежали виявлення сервісів, планування й секрети | Спільні частини платформи — єдині точки відмови, зокрема й для моніторингу (рядок 12) |
| AWS us-east-1, 2025 | Порожній DNS-запис DynamoDB виправили за три години; далі робота з відновлення EC2 відвалювалася за таймаутом і ставала в чергу знову, доки інженери її не притримали | Повтори можуть тримати систему лежачою вже після того, як причина зникла (рядки 2–3) |
Історія Monzo починається як безпековий проєкт, а закінчується уроком про знання. У листопаді 2019 року безпекова команда банку хотіла, щоб сервіс, який керує зображеннями на «скарбничках», не міг звертатися до сервісу, що переказує гроші. З кількома сервісами список дозволів можна вести вручну. У Monzo їх було понад 1500, між ними — понад 9300 унікальних з’єднань, і список змінювався щодня. Ні в кого його не було. Тож команда написала rpcmap — інструмент, що читає Go-код кожного сервісу й знаходить виклики, які той робить до інших. Він генерує окремий файл правила на кожен викликаний сервіс і перевіряє ці файли на кожному push, а власники критичних сервісів можуть вимагати перегляду кожного нового викликача. Першим закрили реєстр. Урок ширший за безпеку: у великій системі сервісів справжній граф залежностей живе лише в коді, доки інструмент його не витягне, а без цього графа на рядок 16 не відповісти.
Uber — та сама проблема в більшому масштабі. До липня 2020 року компанія мала близько 2200 критичних мікросервісів, і її інженери прямо описали ціну. Сервіси стали чорними скриньками, чия поведінка могла змінитися будь-коли. Виклики йшли на багато рівнів углиб, тож сплеск затримки в одній залежності каскадом ішов угору. Пошук однієї першопричини вимагав пройти близько 50 сервісів, якими володіли 12 команд. Відповідь — Domain-Oriented Microservice Architecture — не злила сервіси. Вона їх згрупувала: пов’язані сервіси утворюють домен, домени утворюють шари, що обмежують, хто від кого може залежати, а до кожного домену звертаються через один шлюз. Uber розклав свої 2200 сервісів по 70 доменах і повідомив, що підключення нової фічі до платформи стало на 25–50% швидшим. Ще одне число з тексту варто запам’ятати: Uber виміряв період напіврозпаду мікросервісу — 1,5 року. Половину з них замінювали кожні півтора року, і шлюзи не давали кожній заміні стати міграцією для її викликачів.
Де це вироджується
Мікросервіси відмовляють публічно. Моноліт гниє тихо впродовж року; набір сервісів показує своє слабке місце протягом першої поганої години. Майже кожен збій — одне з цього:
- Спільна база даних, що перетворює набір сервісів на розподілений моноліт (рядок 7).
- Сервіси, названі за технічними шарами: кожна фіча зачіпає всі, і ніщо не виходить окремо.
- Релізи, що вимагають випуску кількох сервісів у фіксованому порядку, — це і є визначення відсутньої незалежності.
- Довгі ланцюги синхронних викликів, де доступність множиться вниз — нижче, ніж була в моноліті.
- Повтори на кожному рівні — у клієнті, у бібліотеці й у сітці, — що множаться в шторм (рядок 2).
- Повтори без ключів ідемпотентності, що дублюють побічні ефекти саме за тих умов, заради яких повтори існують (рядок 5).
- Код «зберегти, потім опублікувати» без outbox, що губить подію щоразу, коли процес помирає не в той момент (рядок 9).
- Саги, у яких ніхто не спитав, що бачить паралельний запит посеред процесу (рядок 8).
- Шлюз, що оброс бізнес-логікою, тож він знову моноліт — лише з додатковим переходом.
- Один сервіс на розробника, що дає топологію, яка відображає найм, а не предметну область.
- Відсутність розподіленого трасування, що перетворює кожен міжсервісний інцидент на археологію (рядок 15).
Чесна межа в тому, що мікросервіси розв’язують організаційну проблему технічним механізмом. Якщо обмеження в тому, що дванадцять команд не можуть випускати зміни без узгодження, стиль його знімає й вартий свого рахунку. Якщо обмеження в тому, що код заплутаний, деплої страшні чи база повільна, стиль додає до проблеми мережу й виставляє за неї рахунок щомісяця. Мережа, яка робить межу дорогою для перетину, робить її й дорогою для переміщення. Хибна межа в моноліті коштує рефакторингу; між сервісами — міграції. І навіть компанії, які вміють це робити, зрештою знову мислять більшими одиницями, як Uber зі своїми 70 доменами.
Практична перевірка займає пів дня. Візьміть нещодавню фічу й порахуйте сервіси, які вона зачепила. Знайдіть реліз за минулий місяць, що вимагав деплою двох сервісів разом. Перевірте, чи кожен вихідний виклик має таймаут і чи повтори відбуваються більше ніж на одному рівні. Пошукайте в коді подію, яку публікують одразу після запису в базу без outbox. Спитайте, кого будять для кожного сервісу і чи немає сервісу з кількома власниками або без жодного. І простежте один запит, що впав, від початку до кінця: якщо це займає понад десять хвилин, рядок 15 — перше, що треба лагодити.
Коли це застосовувати
Застосовуйте, коли
- Кілька команд справді блокують одна одну на спільному деплої, і ціну цього виміряно.
- Частини системи мають справді різні профілі масштабування, цілі доступності чи межі відповідності.
- Автоматизований деплой, розподілене трасування й швидке створення середовищ уже працюють.
- Команди можуть самі експлуатувати свої сервіси в продакшні, зокрема поза робочими годинами.
- Бізнес може сказати, що має бачити користувач, поки два сервіси ненадовго неузгоджені.
Уникайте, коли
- Невелика команда — проблеми координації, яку це розв’язує, ще немає, а рахунок однаково прийде.
- Межі предметної області ще не зрозумілі, тож межі сервісів були б здогадами, які дорого пересувати.
- Справжня проблема — заплутаний код: поділ по наявній зв’язності дає його розподілену версію.
- Деплой досі ручний, і ручний крок помножиться на кількість сервісів.
- Сувора узгодженість усієї системи — бізнес-вимога, а не звичка.
Джерела й метод
На чому стоїть ця стаття
- 19 джерел
- 3 задокументовані збої
- Перевірено 13 жовтня 2026 р.
Збої, на яких вчиться стаття
Kinesis, Roblox і us-east-1 у «П’ять кейсів і те, чого в кожному бракувало»- ПостмортемSummary of the Amazon Kinesis Event in the Northern Virginia (US-EAST-1) Region (відкривається в новій вкладці)Amazon Web Services · 25.11.2020
- ПостмортемRoblox Return to Service 10/28-10/31 2021 (відкривається в новій вкладці)Roblox · 20.01.2022
- ПостмортемSummary of the Amazon DynamoDB Service Disruption in the Northern Virginia (US-EAST-1) Region (відкривається в новій вкладці)Amazon Web Services · 10.2025
Практики й походження термінів
визначення, передумови й патерни для викликів і даних- СтаттяJames Lewis, Martin Fowler — Microservices (відкривається в новій вкладці)martinfowler.com · 25.03.2014
- СтаттяMartin Fowler — MicroservicePrerequisites (відкривається в новій вкладці)martinfowler.com · 28.08.2014
- СтаттяMartin Fowler — MicroservicePremium (відкривається в новій вкладці)martinfowler.com · 13.05.2015
- СтаттяJim Gray — A Conversation with Werner Vogels (відкривається в новій вкладці)ACM Queue · 30.06.2006
- ДослідженняHector Garcia-Molina, Kenneth Salem — Sagas (відкривається в новій вкладці)ACM SIGMOD 1987 · 1987
- ГайдChris Richardson — Pattern: Saga (відкривається в новій вкладці)microservices.io
- ГайдChris Richardson — Pattern: Transactional outbox (відкривається в новій вкладці)microservices.io
- ГайдMarc Brooker — Timeouts, retries, and backoff with jitter (відкривається в новій вкладці)Amazon Builders’ Library
- ГайдSite Reliability Engineering — Handling Overload (відкривається в новій вкладці)Google
- КнигаMichael T. Nygard — Release It!Pragmatic Bookshelf · 2007
- ДокументаціяNetflix/Hystrix (відкривається в новій вкладці)GitHub
- СтандартTrace Context (відкривається в новій вкладці)W3C · 23.11.2021
- ДокументаціяOpenTelemetry — CNCF project page (відкривається в новій вкладці)Cloud Native Computing Foundation
- СтаттяAnnouncing Istio 1.24.0 (відкривається в новій вкладці)istio.io · 11.2024
Monzo і Uber
два інші кейси: як жити з багатьма сервісамиДослідження з Claude. Пошук і звірку першоджерел зроблено з Claude (Anthropic). Відбір, текст і перевірку фактів — редакція Anatomy of IT Product.
Було корисно?
Поділіться з тим, хто працює над тією ж задачею.