Компроміси микросервисов

Від перекладача: з моменту виходу популярної статті Мартіна Фаулера «Микросервисы» переклад на Хабре) пройшло вже достатньо часу, щоб автор міг доповнити свої спостереження свіжим досвідом проектування і розробки микросервисов в різних компаніях, і розповісти про нього в новому пості, чий переклад представляється вашій увазі.
imageБагато команди розробників знайшли архітектурний стиль микросервисов підходом, переважаючим монолітну архітектуру; інші команди з'ясували, що для них микросервисы — зайвий тягар, підриває продуктивність розробки. Як і у будь-якого стилю архітектури, у микросервисов є свої плюси і мінуси. Для того, щоб робити усвідомлений вибір, ви повинні розуміти ці властивості і вміти розглядати їх на тлі власних конкретних умов.
Микросервисы дають переваги... … ціною витрат
Жорсткі межі модулів
Strong Module Boundaries

Микросервисы підсилюють модульну структуру, що особливо важливо для великих команд розробників.
Розгалуженість
Distribution

Розподілені системи важче програмувати, оскільки віддалені виклики повільні і завжди ризикують невдачею-відмовою.
Незалежний деплоймент
Independent Deployment

Прості сервіси простіше деплоить, і, оскільки вони автономні, менше ймовірність відмови системи в разі, якщо щось йде не так.
Узгодженість в кінцевому рахунку
Eventual Consistency

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

З микросервисами ви можете змішувати кілька мов, фреймворків та технологій зберігання даних.
Експлуатаційна складність
Operational Complexity

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

Жорсткі межі модулів

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

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

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

Як я говорив раніше, не існує такої причини, з якої монолітна система повинна будуватися без хорошої модульної структури. [1] Але численні спостереження показують, що подібне робиться досить-таки рідко, оскільки Великий грудку бруду (Big Ball of Mud — це найпопулярніший архітектурний патерн. Фрустрація від цього явища, разом з однаково сумною долею багатьох монолітів, призвела окремі команди розробників на шлях микросервисов. Принцип незалежності модулів працює тому, що межі модуля служать бар'єром для посилань між модулями. Проблема полягає в тому, що у випадку з монолітною системою не становить особливої праці підлізти під цей бар'єр; подібний вчинок може бути корисним тактичним прийомом, надаючи короткий шлях до швидкої розробки та запуску якихось функцій системи, але в перспективі це підриває основи модульної структури і істотно погіршує продуктивність команди. Розкладання модулів по різних сервісів робить кордону твердіше, створюючи додаткові перешкоди на шляху любителів сумнівних рішень для зрізання шляху.

Важливим аспектом цього зв'язку є сталість даних (persistent data). Одна з ключових характеристик микросервисов — це децентралізоване управління даними; цей принцип означає, що кожен сервіс управляє своєю базою даних і будь-який інший сервіс повинен використовувати API цього сервісу, щоб дістатися до неї. Подібне рішення дозволяє позбутися інтеграційних баз даних, які є основними джерелами неприємних зв'язків у великих системах.

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

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

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

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

Один почутий мною кейс був досить цікавим. Команда зробила неправильний вибір, використавши микросервисы для системи, яка не була достатньо складною, щоб отримати від цього рішення вигоду. Проект потрапив в біду, і його треба було рятувати, тому на нього було кинуто ще більше людей. У цей момент микросервисная архітектура несподівано повернулася позитивною стороною: система змогла проковтнути приплив розробників, і команда могла керувати розробкою набагато простіше, ніж зазвичай буває в аналогічних випадках з монолітними архітектурами. У результаті, проект прискорилося до більшої продуктивності, ніж можна було б очікувати навіть від моноліту, даючи команді шанс надолужити згаяне. Результат виявився негативним — підсумкове ПО коштувало більше людино-годин, ніж якщо б воно було побудовано монолітом; однак, микросервисы показали свою здатність до нарощування швидкостей.

Розгалуженість

Отже, микросервисы використовують розподілену систему для поліпшення модульності. Але розподілене ПО має великий недолік: він полягає в тому факті, що воно розподілене. Як тільки ви разыграете карту роздрібненості, ви накликаєте на себе багато складнощів. Навряд чи комьюніті навколо микросервисов ставиться до цих витрат так само наївно, як рух за розподілені об'єкти в свій час, але складнощі від цього нікуди не йдуть.

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

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

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

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

І це я перерахував лише два найважливіших омани про розподілених обчисленнях російською).

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

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

Узгодженість в кінцевому рахунку

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

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

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

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

Світ монолітів теж вільний від цих проблем. Із зростанням систем, з'являється все більша необхідність в кешуванні для покращення продуктивності, а инвалидация кеша — це ще одна Складна Проблема. Більшість додатків потребує автономних блокування для уникнення довгоіснуючих транзакцій бази даних. Зовнішні системи потребують оновлення, які не можуть бути погоджені за допомогою менеджера транзакцій. Бізнес-процеси набагато терпиміше до неузгоджень, ніж ви думаєте, оскільки бізнеси частіше віддають перевагу доступності (бізнес-процеси давно мали інтуїтивним розумінням CAP-теореми).

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

image

Незалежний деплоймент

Компроміси між модульними кордонами і складнощами розподілених систем переслідують мене всю мою кар'єру в цьому бізнесі. Але найбільш значна зміна за останні десять років — це зростаюча роль релізу в продакшн. У двадцятому столітті релізи в продакшн повсюдно були болючим і рідкісним подією, коли всі затримувалися на роботі на ніч або на вихідні для того, щоб засунути незвичайний шматочок ПО туди, де він зможе робити щось корисне. Проте, в наші дні досвідчені команди часто релизятся в продакшн, і багато організації практикують Continuous Delivery, що дозволяє їм робити продакшн релізи багато разів за день.

Цей зсув мав глибокий вплив на індустрію розробки ПЗ, і він тісно переплетений з рухом микросервисов. Окремі випадки спроби створення микросервисов були спровоковані складністю деплоя великих монолітів, коли невелика зміна в частині моноліту могло призвести до невдачі деплоймента проекту в цілому. Ключовий принцип микросервисов полягає в тому, що сервіси — це компоненти, які можна деплоить окремо; тож тепер, коли потрібно зробити зміну, необхідно протестувати і задеплоить тільки маленький сервіс. У разі невдачі ви не покладете всю систему. Зрештою, з-за проектування під відмова, навіть повна відмова компонента не повинен перешкоджати роботі інших частин системи, нехай навіть з деякою витонченої деградацією (graceful degradation).

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

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

Незважаючи на те, що багато людей називають continuous delivery однією з причин вибору микросервисов, необхідно пам'ятати, що навіть великі моноліти теж можуть бути доставлені безперервно; найвідоміші випадки — Facebook і Etsy. Також бракує випадків, коли спроби переходу на микросервисную архітектуру спотикаються про незалежний деплоймент, коли для декількох сервісів потрібно уважно координувати їх релізи [2]. Незважаючи на те, що я постійно чую про те, що continuous delivery з микросервисами стає простіше, сам я не дуже переконаний в цьому; велику практичну цінність несе модульність — хоча зазвичай модульність тісно пов'язана зі швидкістю релізів.

Експлуатаційна складність

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

Це посилює роль continuous delivery. Якщо для монолітів continuous delivery — просто корисна штука, майже завжди варта витрачених на неї зусиль, то в разі серйозної микросервисной архітектури — це вже життєва необхідність. Без автоматизації та співпраці, що передбачає continuous delivery, впоратися з десятками сервісів буде неможливо. Експлуатаційна складність також зростає із-за зростаючої потреби управління цими сервісами та їх моніторингом. І знову, тут ці необов'язкові показники рівня зрілості монолітів стають необхідністю, якщо ми домішуємо до справи микросервисы.

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

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

Але і необхідність просунутих навичок і коштів не є найскладнішою частиною управління експлуатаційною складністю. Для того, щоб робити це ефективно, потрібно впроваджувати в культуру компанії девопс: серйозно поліпшувати ступінь взаємодії розробників, експлуатації і всіх відповідальних за реліз. Зміни культури в компанії — тема болюча, особливо для великих і старих організацій. Якщо ви не проведете ці зміни в частині навичок і культури, то, у разі монолітних додатків, процес буде просуватися з труднощами; у разі ж микросервисов — він буде серйозно травмований.

image

Технологічне різноманітність

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

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

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

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

Вторинні фактори

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

Микросервисы дозволяють відокремити конфіденційні дані і використовувати їх більш безпечно. Більш того, за рахунок забезпечення того, що весь трафік між микросервисами захищений, микросервисный підхід може зробити експлоїт більш важким завданням. По мірі зростання важливості фактора безпеки, з часом це може стати важливою причиною використання микросервисов. Для переважно монолітних систем немає нічого незвичайного в тому, щоб створювати окремі сервіси для роботи з конфіденційними даними.

Підбиття підсумків

Будь-який пост, що стосується будь-якого архітектурного стилю і носить загальний характер, буде страждати від обмежень ради загального плану. Читання постів на зразок цього не зможе дати вам конкретну відповідь; однак, подібні статті допоможуть переконатися, що ви в курсі тих важливих чинників, які вам слід взяти до уваги для майбутнього вибору. Кожен перерахований фактор буде мати різну вагу для різних систем, причому іноді плюси і мінуси будуть мінятися місцями (наприклад, суворі кордони модулів гарні в більш складних системах, але стають перешкодою для простих). Будь-яке ваше рішення буде залежати від застосування критеріїв до ваших конкретних умов — від значимості для вашої системи і впливу на неї в перспективі. Крім того, наш досвід з микросервисной архітектурою відносно невеликий. Зазвичай судити про архітектурних рішеннях можна не раніше, перш ніж система «подорослішає» і ви зрозумієте, як працювати з нею через роки після початку розробки; поки що у спільноти не набралося достатньої кількості анекдотів про системах-довгожителях, заснованих на микросервисных архітектурах.

Моноліти і микросервисы — це не чорно-білий вибір. Обидва визначення — нечіткі, а це означає, що багато системи будуть лежати в зоні розмитою кордону. Будуть і системи, які не впишуться в одну з категорій. Більшість, включаючи мене самого, говорить про микросервисах в контрасті з монолітами, тому що має сенс протиставляти їх більше звичного стилю; однак, ми повинні пам'ятати, що існують системи, які не вписуються ні в одну з цих категорій. Я розмірковую про монолітах і микросервисах як про двох областях в одному великому просторі архітектур. Ці області заслуговують позначення тому, що у них є цікаві характеристики, за якими їх можна обговорювати і порівнювати, але жоден компетентний архітектор не стане розглядати їх як повноцінне поділ всього архітектурного простору.

Основним висновком, який повинен бути широко прийнятий громадськістю, має стати визнання факту Микросервис Преміум: микросервисы накладають ціну на продуктивність, яка може бути скомпенсирована тільки в більш складних системах. І якщо ви можете впоратися зі складністю вашої системи за допомогою монолітної архітектури, то ви не повинні вдаватися до використання микросервисов.

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

Додаткова література

У книзі Сема Ньюмана «Створення микросервисов» у першій главі наводиться докладний список переваг микросервисной архітектури.

Пост Бенджаміна Вутэна «Микросервисы: безкоштовних ланчів не буває!» High Scaleability відомий як один з перших і все ще кращий список недоліків микросервисов.

Примітки

1. Деякі люди вважають термін «моноліт» образою, завжди припускаючи під ним бідну модульну структуру. У світі микросервисов більшість не вкладають у термін цього сенсу; вони визначають «моноліт» чисто як додаток, побудоване як окрема одиниця. Звичайно, окремі затяті шанувальники микросервисов впевнені в тому, що більшість монолітів закінчує свій шлях Великими грудками бруду, але я не зустрічав жодного, хто зміг би спростувати тезу про те, що побудувати добре структурований моноліт цілком можливо.

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

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.