РозробкаSenior

Моноліт → мікросервіси

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

Патерн
Strangler fig
Одиниця роботи
Одне виділення
Найскладніше
Поділ даних

Почніть з обмеження, а не з цілі

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

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

Патерн strangler fig

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

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

Фасад ставлять першим — до того, як щось виділено. Цей порядок важливий: із фасадом на місці перше виділення є зміною маршрутизації, і відкат — теж. Без нього перше виділення є зміною в кожному викликачі, і відкат — ще однією зміною в кожному викликачі.

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

Що виділяти першим

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

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

Поділ даних

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

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

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

Дві техніки, що роблять більшість роботи

Прошарок проти псування

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

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

Закон Конвея, застосований свідомо

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

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

Коли зупинитися

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

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

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

Як це виявляється в реальній поставці

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

Де вона вироджується

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

Коли це застосовувати

Застосовуйте, коли

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

Уникайте, коли

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

Було корисно?

Поділіться з тим, хто працює над тією ж задачею.