Перехід на мікросервіси: власний досвід, переваги та недоліки
Привіт, мене звати Андрій Береза. Я — Architect в SPD Technology, маю 12 років досвіду в IT, працюю з продуктом у галузі фінтех та хочу поділитися досвідом переходу з монолітної архітектури на мікросервісну, зокрема — з монолітного бекенду.
Детальніше про технічні виклики й на що потрібно звернути увагу під час переходу розповім на прикладах у матеріалі. Маю надію, що цей досвід стане у пригоді для команд, які тільки міркують над подібним переходом та хочуть зібрати повну картину вхідних даних, щоб уникнути помилок.
Як цей процес починався. Причини переходу
Шість років тому, коли ми почали процес переходу, продукт складався з моноліту, який називався «платформа». Це був масив даних з майже мільйоном рядків коду, у якому працювали всі команди. Та з часом такий підхід для нас почав приносити низку незручностей.
По-перше, було незрозуміло, хто відповідав за певну частину коду; по-друге, стало важко передбачити наслідки змін у великому моноліті, який має дев’ятирічну історію; по-третє, ми хотіли далі масштабувати продукт та команду, і перші дві проблеми тільки поглиблювалися.
Тому для початку нам треба було вирішувати, як зробити так, аби команди могли працювати незалежно, та як продукт з такою «багатою» історією зміг би, не знижуючи темпи розвитку, витримувати ще більші навантаження і спокійно масштабуватися далі.
Технічні виклики на шляху
Складна доменна сфера
Через те, що наш продукт — це масштабна екосистема, яка має безліч додаткових сервісів та щільну взаємодію між кожним елементом, одним з головних челенджів переходу була складна доменна сфера.
Наприклад, якщо почати ділити на домени проєкт інтернет-магазину, то все доволі легко — є товари, покупки, список бажань користувача тощо. У нашому ж випадку цей процес був і все ще залишається важким, бо перед нами постає складний вибір: що є окремим доменом — бізнес сутність чи бізнес-кейс, і яка команда повинна ним володіти?
Наприклад, є поняття «інвестиції», в якому є компанія, в яку інвестують, і є інвестор, й іноді не зрозуміло, чи це має належати до домену «інвесторів», чи до «компаній», чи взагалі бути окремим доменом «інвестування». І подібних ситуацій безліч.
Тож аби чітко визначити, яка частина продукту буде більш вірогідно розвиватися окремо від інших та чи можна її виділити в окремий домен, нам потрібно було зібрати достатньо знань про реальний світ інвестицій, про органічне зростання продукту, причини реалізації попередніх рішень, узагальнити модель роботи кінцевих користувачів та стратегію подальшого розвитку всієї продуктової екосистеми.
Стандартизація підходів
Додатковим викликом було розповсюдження нових стандартизованих підходів між командами.
Якщо до цього у нас була одна кодова база з однаковими підходами від самого її започаткування, та знання передавалися «з покоління в покоління», коли з’явилися мікросервіси — виникла необхідність описувати нові стандарти.
Наприклад, які фреймворки використовуємо під час роботи, в якому стилі пишемо код тощо. Хоч і однією з особливостей мікросервісів є можливість використання різних технічних стеків, для себе ми визначили, що будемо працювати з уже напрацьованою і стандартною зв’язкою Java + Spring для 90% системи.
На скейлі такі обмеження мають відчутний бізнес-вплив, і їх треба застосовувати усвідомлено. У цьому разі за критичної необхідності люди з однієї команди можуть переходити в іншу зі збереженням перфомансу в делівері. Це важливо, особливо, коли пріоритети можуть змінюватися відносно часто, тож на цьому етапі для нас таке рішення є рятівним.
У процесі дотримання узгодження нам допомагали й допомагають регулярні зустрічі для всіх охочих розробників, де всі діляться підходами, новинами та можуть винести питання і пропозиції на обговорення. Тому якихось прихованих і неузгоджених інновацій в стеку чи технологіях у нас мінімум.
Утворення DevOps команди
Ріст кількості сервісів, які треба деплоїти, призвів до ускладнення всієї інфраструктури, яку необхідно налаштувати, стандартизувати та забезпечити інструментами, а головне — навчити розробників працювати з цим всім.
Це не було проблемою, скоріше доволі складною і тривалою задачею, що затягнулася майже на рік, а може і більше. Тільки тоді основні кроки в напрямі інфраструктури були зроблені. Усім, що описано вище, займалась новостворена команда DevOps.
Налаштування процесу моніторингу
Моніторинг є важливою передумовою для переходу на мікросервіси. Бо для того, щоб зрозуміти, що відбувається в системі з купою рухомих частин, без, як мінімум, метрик і логування неможливо обійтись. В ідеалі б мати ще Distributed Tracing, але навіть просто коли Trace Id в логах — це величезне полегшення життя.
Ця задача також лягла на вже і так навантажені плечі DevOps, але вони з нею чудово впоралися (за стандартами того часу).
Нові технічні рішення: підхід Back-end for Front-end
Декілька років ми ударними темпами нарощували кількість мікросервісів, а з ними паралельно зростала і кількість функціонала на нашому основному вебзастосунку (платформі). Тож через деякий час ми зрозуміли, що навіть прошарок, який просто бере дані з мікросервісів, агрегує і трансформує їх у вигляд, який потрібен для Front-end, дуже розширився, і з’явилася потреба розібратися і з цим.
Спочатку ми пішли шляхом, коли команди комітили в один моноліт з цим вебзастосунком, але дуже швидко всі почали наступати одне одному на ноги, почались непорозуміння, розсинхрон тощо. Ми вирішили розділити його на частини, відповідно до фіч, і кожну частину віддати в ту команду, що володіє відповідною фічою, асоційованою з «доменом».
Це не новий підхід, у світі він називається Back-end for Front-end (BFF). На той момент Front-end в нас ще був монолітний, і для того, щоб зробити цю розбивку непомітною для нього та нічого не зламати, ми вбудували API Gateway поперед усіх BFF: тобто Front-end код робить запити на API Gateway, а той вже знає, на який саме BFF його перенаправляти залежно від url. Наприклад, якщо вона (url) починається з profiles/ — API Gateway передає запит на Profile BFF.
Факапи у процесі переходу
Не все було так гладко під час переходу, як хотілося. Наприклад, в нашому продукті існує один величезний пошуковий engine. Він називається Advanced Search і вміє шукати, фільтрувати, сортувати й агрегувати майже всі бізнес-дані, які є в нашій системі.
Коли перед нами стояла задача швидко розширити команду, і ми змогли це зробити лише в Києві (основна частина спеціалістів тоді була — і здебільшого зараз перебуває — в Черкасах), треба було вирішувати, над якою частиною будуть працювати нові колеги.
Зрештою ми віддали їм частину, що відображає результати цього Advanced Search. А частину, що шукає у даних, Search Engine, залишили для команди в основній локації через специфіку експертизи і неможливості її легкої передачі.
І, сюрприз-сюрприз, виявилось, що для внесення змін між ними повинна бути тісна комунікація, бо щойно додаються нові дані в системі, їх треба одночасно додати і в ці два компоненти, а ще тестувати та релізити.
Таке переважно штучне розділення породило тонну надлишкових координацій, конфліктів та знизило загальну ефективність технічного рішення системи пошуку, зокрема внаслідок необхідності введення формального АРІ, на якому втрачається додатковий час як під час розробки, так і під час міжсервісної взаємодії при обміні величезними об’ємами даних.
Додам маленьку ремарку, що на той час не було взагалі такого поняття як «ремоут», усі команди працювали в різних офісах та містах. Зараз це вже одна команда, що володіє обома частинами, а цей компонент пошуку має шанс трансформуватися в більш ефективний уніфікований компонент відповідно до reverse Convey Law.
Насправді хиб та помилок було чимало, але всі вони були дрібними, локальними, бо сам процес переходу від моноліта достатньо непростий і іноді дуже рутинний, але доволі передбачуваний, якщо послідовно дотримуватися критеріїв щодо лінії розділення. Коли я ще був розробником, то, бувало, засідав на декілька місяців, щоб відокремити певний мікросервіс з моноліта.
Переваги мікросервісів
Можливість масштабування. Команди можуть планувати, розробляти та деліверити кожен свою частину, максимально незалежно від інших команд.
Здатність витримувати більше навантаження. Через те, що мікросервіси легко масштабуються, то можна, піднімаючи кількість інстансів, витримати більшу кількість користувачів і даних.
Поєднання різних мов програмування. У мікросервісній архітектурі використання декількох мов програмування не є проблемою. Наприклад, в нашому продукті добре співпрацюють Java, Kotlin та Python, розв’язуючи конкретні задачі найкращим чином.
Відповідальність команди за власний мініпродукт. Я помітив, що після переходу команди прагнуть дати ще якісніший результат в роботі над своїм сервісом, завдяки більшому розумінню, що вони відповідають за весь ланцюг створення і підтримки технічного та функціонального рішення.
Недоліки мікросервісів
Збільшення когнітивного навантаження. Якщо в моноліті треба лише знати, як додати код в наявний сервіс, то з мікросервісами розробники повинні вміти розгортати та підтримувати нові сервіси, а також пам’ятати про своє оточення і залежності.
Складність інфраструктури. З монолітом стандартизація інфраструктури не дуже потрібна через те, що компонентів дуже мало, і можна їх деплоїти, моніторити, як забажається. Мікросервіси потребують стандартних підходів у всьому — деплойменті, моніторингу, build-процесі тощо.
Підтримка технічного стека в актуальному стані. З ростом кількості сервісів виникає більше репозиторіїв, в яких необхідно оновлювати бібліотеки й технічний стек.
Цього можна не робити, але тоді треба враховувати, що за впровадження якихось загальних бібліотек або підходів варто взяти до уваги весь спектр версій технічного стека. Згадати б просто Log4shell вразливість і 100+ сервісів, де треба проапдейтити ліби.
Ненадійність мережі. Якщо в моноліті ви на 99% впевнені, що за умови виклику методу виконається очікуваний код, то з мікросервісами ви повинні бути на 99% готовими, що рано чи пізно він не виконається:)
Для цього треба підстрахуватися та на всіх викликах мати retry, timeout, а також circuit breaker, щоб в разі чого не перевантажувати додатково сервіс. (І бажано це якось протестувати ще до продакшена).
Необхідність розуміння меж доменів. Це не недолік, але передумова. Коли проєкт тільки починається, не завжди зрозуміло, де закінчується один домен, а де починається інший.
Якщо почати розробку в мікросервісному стилі без цього розуміння і неправильно поділити на домени, можна потрапити в ситуацію, коли розробка потребуватиме величезної кількості мітингів, координації й технічних «милиць».
Висновок
Попри всі технічні виклики на шляху до мікросервісної архітектури, на цей момент 90% нашої системи вже є мікросервісною архітектурою. А 10 % — це все ще моноліти, які поки не до кінця задекаплені.
Їх також можна розділити на окремі мікросервіси, проте ми цього не робимо. Бо, по-перше, це не пріоритет, по-друге, ці шматочки статичні, тобто в них нічого не змінюється і не додається нового.
Взагалі розділення моноліта на мікросервіси технічно нескладне. Єдина проблема визначити, коли це робити та кому це робити. І чи є сенс для бізнесу це робити? Адже монолітна і мікросервісна архітектури це не етапи еволюції, а просто дві архітектурні парадигми, які використовуються для різних організаційних структур і схем масштабування.
66 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів