Как да не се простреляте в крака с Liquibase

Никога не се е случвало и ето го отново!

При следващия проект решихме да използваме Liquibase от самото начало, за да избегнем проблеми в бъдеще. Както се оказа, не всички млади членове на екипа знаят как да го използват правилно. Направих вътрешен семинар, който след това реших да превърна в статия.

Тази статия включва полезни съвети и описания на три от най-очевидните клопки, в които можете да попаднете, когато работите с инструменти за мигриране на релационни бази данни, по-специално Liquibase. Предназначен за Java разработчици от младше и средно ниво, за по-опитни разработчици може да бъде интересно да структурират и повтарят това, което най-вероятно вече е известно.

Как да не се простреляте в крака с Liquibase

Liquibase и Flyway са основните конкурентни технологии за решаване на проблемите с контрола на версиите на релационни структури в света на Java. Първият е напълно безплатен, на практика се избира по-често за използване, поради което Liquibase беше избран за герой на публикацията. Въпреки това, някои от описаните практики може да са общи в зависимост от архитектурата на вашето приложение.

Релационните миграции са принудителен начин за справяне със слабата гъвкавост на релационните хранилища на данни. В ерата на модата за ООП, стилът на работа с базата данни означаваше, че ще опишем схемата веднъж и няма да я докосваме отново. Но реалността винаги е, че нещата се променят и промените в структурата на таблиците са необходими доста често. Естествено, самият процес е болезнен и неприятен.

Няма да се задълбочавам в описанието на технологията и инструкциите за добавяне на библиотека към вашия проект, достатъчно статии са написани по тази тема:

Освен това вече имаше страхотна статия по темата за полезни съвети:

Советы

Искам да споделя моите съвети и коментари, родени с потта, кръвта и болката при решаването на проблемите с миграцията.

1. Преди да започнете, трябва да прочетете раздела за най-добри практики уебсайт Liquibase

там описани са прости, но много важни неща, без които използването на библиотеката може да усложни живота ви. Например, неструктурният подход към управлението на набор от промени рано или късно ще доведе до объркване и неуспешни миграции. Ако не внедрите взаимно зависими промени в структурата на базата данни и логиката на услугите едновременно, тогава има голяма вероятност това да доведе до червени тестове или счупена среда. Освен това препоръките за използване на Liquibase на официалния уебсайт съдържат параграф за разработването и проверката на скриптове за връщане назад заедно с основните скриптове за миграция. Ами в статията https://habr.com/ru/post/178665/ има примери за код, свързан с миграции и механизма за връщане назад.

2. Ако сте започнали да използвате инструменти за миграция, не позволявайте ръчни корекции в структурата на базата данни

Както се казва: "Веднъж Persil, винаги Persil." Ако основата на вашето приложение е започнала да се управлява от инструментите на Liquibase, всички ръчни промени незабавно водят до непоследователно състояние и нивото на доверие в наборите от промени става нула. Потенциални рискове - няколко часа, прекарани за възстановяване на базата данни, в най-лошия случай - мъртъв сървър. Ако вашият екип има DBA архитект от „старата школа“, търпеливо и замислено му обяснете колко лоши ще бъдат нещата, ако той просто редактира базата данни по свой начин от условния SQL разработчик.

3. Ако наборът от промени вече е изпратен в хранилището, избягвайте редактирането

Ако друг разработчик изтегли и приложи набор от промени, който ще бъде редактиран по-късно, той определено ще ви запомни с добра дума, когато получи грешка при стартиране на приложението. Ако редактирането на набора промени по някакъв начин изтече в разработката, ще трябва да слезете по хлъзгавия наклон на актуалните корекции. Същността на проблема се основава на валидирането на промените чрез хеш сума - основният механизъм на Liquibase. Когато редактирате кода на набора промени, хеш сумата се променя. Редактирането на набори от промени е възможно само когато е възможно да се разположи цялата база данни от нулата, без да се губят данни. В този случай рефакторингът на SQL или XML код може, напротив, да улесни живота, да направи миграциите по-четими. Пример може да бъде ситуация, когато в началото на приложението схемата на изходната база данни е координирана в екипа.

4. Имайте проверени резервни копия на базата данни, ако е възможно

Тук, мисля, всичко е ясно. Ако изведнъж миграцията е била неуспешна, всичко може да бъде върнато обратно. Liquibase има инструмент за връщане назад, но скриптовете за връщане назад също са написани от самия разработчик и те могат да имат проблеми със същата вероятност, както при основните скриптове за набор от промени. Това означава, че безопасното използване на резервни копия е полезно във всеки случай.

5. Използвайте проверени резервни копия на базата данни в разработката, ако е възможно

Ако това не противоречи на договорите и поверителността, в базата данни няма лични данни и тя не тежи като две слънца - преди да я приложите на сървъри за миграция на живо, можете да проверите как работи на машината на разработчика и да изчислите почти 100% потенциални проблеми по време на миграция.

6. Разговаряйте с други разработчици от екипа

В добре организиран процес на разработка всеки в екипа знае кой какво прави. В действителност това често не е така, следователно, ако подготвяте промени в структурата на базата данни като част от вашата задача, препоръчително е допълнително да уведомите целия екип за това. Ако някой прави промени паралелно, трябва да се организирате внимателно. Струва си да общувате с колеги дори в края на работата, не само в началото. Много потенциални проблеми с набори от промени могат да бъдат разрешени на етапа на преглед на кода.

7. Мислете какво правите!

Привидно очевиден съвет, приложим във всяка ситуация. Много проблеми обаче биха могли да бъдат избегнати, ако разработчикът отново беше анализирал какво прави и какво може да повлияе. Работата с миграции винаги изисква допълнително внимание и точност.

капани

Нека сега да разгледаме типичните капани, в които можете да попаднете, ако не следвате горните съвети и какво всъщност трябва да направите?

Ситуация 1. Двама разработчици се опитват да добавят нови набори промени едновременно

Как да не се простреляте в крака с Liquibase
Вася и Петя искат да създадат набор от промени версия 4, без да знаят един за друг. Те направиха промени в структурата на базата данни и пуснаха заявка за изтегляне с различни файлове с набор от промени. По-долу се предлага следният механизъм:

Как да решим

  1. По някакъв начин колегите трябва да се споразумеят за реда, в който трябва да вървят техните набори от промени, да кажем, че първо трябва да се приложи Petin.
  2. Единият трябва да излее другия и да маркира промените на Vasya с версия 5. Това може да стане чрез Cherry Pick или чисто сливане.
  3. След промените не забравяйте да проверите валидността на предприетите действия.
    Всъщност механизмите на Liquibase ще ви позволят да имате два набора промени версия 4 в хранилището, така че можете да оставите всичко както е. Тоест просто ще имате две ревизии на версия 4 с различни имена. С този подход версиите на базата данни стават много трудни за навигация по-късно.

Освен това Liquibase, подобно на домовете на хобитите, пази много тайни. Един от тях е ключът validCheckSum, който се появи от версия 1.7 и ви позволява да посочите валидна хеш стойност за конкретен набор от промени, независимо какво се съхранява в базата данни. Документация https://www.liquibase.org/documentation/changeset.html казва следното:

Добавете контролна сума, която се счита за валидна за този changeSet, независимо какво се съхранява в базата данни. Използва се предимно, когато трябва да промените changeSet и не искате грешки да се хвърлят в бази данни, на които вече е стартиран (не е препоръчителна процедура)

Да, това не се препоръчва. Но понякога силен светъл магьосник владее и тъмни техники.

Случай 2: Миграция, управлявана от данни

Как да не се простреляте в крака с Liquibase

Да кажем, че не можете да използвате резервни копия на база данни от живи сървъри. Петя създаде набор от промени, тества го локално и с пълна увереност, че е прав, отправи заявка за изтегляне към разработчика. За всеки случай ръководителят на проекта уточни дали Петя го е проверила, а след това го наля. Но внедряването на сървъра за разработка падна.

Всъщност това е възможно и никой не е имунизиран от това. Това се случва, ако модификациите на структурата на таблицата по някакъв начин са свързани с конкретни данни от базата данни. Очевидно, ако базата данни на Петя е пълна само с тестови данни, тогава тя може да не покрива всички проблемни случаи. Например при изтриване на таблица се оказва, че има записи в други таблици по външен ключ, свързани със записи в тази, която се изтрива. Или при промяна на типа колона се оказва, че не 100% от данните могат да бъдат преобразувани в новия тип.

Как да решим

  • Напишете специални скриптове, които ще бъдат приложени веднъж заедно с миграцията и ще приведат данните в правилната форма. Това е общ начин за решаване на проблема с прехвърлянето на данни към нови структури след прилагане на миграции, но нещо подобно може да се приложи и преди, в специални случаи. Този път, разбира се, не винаги е достъпен, тъй като редактирането на данни на живи сървъри може да бъде опасно и дори фатално.
  • Друг труден начин е да редактирате съществуващ набор от промени. Трудността е, че всички бази данни, където вече е приложен в съществуващия си вид, ще трябва да бъдат възстановени. Напълно възможно е целият бекенд екип да бъде принуден локално да навие базата данни от нулата.
  • И най-универсалният начин е да прехвърлите проблема с данните в средата на разработчика, да пресъздадете същата ситуация и да добавите нов набор от промени към повреден, който ще заобиколи проблема.
    Как да не се простреляте в крака с Liquibase

Като цяло, колкото повече базата данни е подобна по състав на базата данни на производствения сървър, толкова по-малка е вероятността проблемите с миграциите да стигнат далеч. И, разбира се, преди да изпратите набора от промени в хранилището, трябва да помислите няколко пъти дали ще счупи нещо.

Ситуация 3. Liquibase започва да се използва, след като влезе в производство

Да предположим, че ръководителят на екипа е помолил Петя да включи Liquibase в проекта, но проектът вече е в производство и вече има структура на база данни.

Съответно, проблемът е, че на всички нови сървъри или машини за разработчици данните от таблицата трябва да бъдат пресъздадени от нулата и вече съществуващата среда трябва да остане в последователно състояние, като е готова да приеме нови набори от промени.

Как да решим

Има и няколко начина:

  • Първият и най-очевиден е да имате отделен скрипт, който трябва да се прилага ръчно при инициализиране на нова среда.
  • Второто, по-малко очевидно, е да имате миграция на Liquibase, която е в различен контекст на Liquibase, и да я приложите. Можете да прочетете повече за Liquibase Context тук: https://www.liquibase.org/documentation/contexts.html. Като цяло, това е интересен механизъм, който може успешно да се приложи, например, за тестване.
  • Третият път се състои от няколко стъпки. Първо трябва да се създаде миграция за съществуващи таблици. След това трябва да се приложи върху някаква среда и така ще се получи нейната хеш сума. Следващата стъпка е да инициализирате празни таблици Liquibase на нашия непразен сървър и можете ръчно да поставите запис на набор от промени „сякаш приложен“ с промените, които вече са в базата данни, в таблицата с хронологията на прилагане на набори от промени. По този начин, на вече съществуващ сървър, историята ще започне от версия 2 и всички нови среди ще се държат идентично.
    Как да не се простреляте в крака с Liquibase

Сценарий 4: Миграциите стават огромни и не могат да се справят

В началото на разработването на услугата, като правило, Liquibase се използва като външна зависимост и всички миграции се обработват при стартиране на приложението. С течение на времето обаче може да се натъкнете на следните случаи:

  • Миграциите стават огромни и отнемат много време за завършване.
  • Има нужда от мигриране в разпределени среди, например на няколко екземпляра на сървъри на база данни едновременно.
    В този случай прилагането на миграции за твърде дълго време ще доведе до изчакване при стартиране на приложението. Освен това прилагането на миграции на базата на екземпляр на приложение може да доведе до това, че различни сървъри са в състояние на несинхронизиране.

Как да решим

В такива случаи вашият проект вече е голям, може би дори възрастен, и Liquibase започва да действа като отделен външен инструмент. Факт е, че Liquibase, като библиотека, се събира в jar файл и може да работи като зависимост в рамките на проекта, както и самостоятелно.

Офлайн можете да оставите прилагането на миграции на вашата CI/CD среда или на силните плещи на вашите системни администратори/внедрители. За да направите това, имате нужда от командния ред Liquibase https://www.liquibase.org/documentation/command_line.html. В този режим става възможно стартирането на приложението след приключване на всички необходими миграции.

Продукция

Всъщност има много повече клопки при работата с миграции на бази данни и много от тях изискват креативен подход. Важно е да разберете, че ако използвате инструмента правилно, повечето от тези капани могат да бъдат избегнати. По-конкретно, трябваше да се сблъскам с всички проблеми, изброени в различни форми, а някои от тях бяха резултат от моите задръствания. По принцип това се случва, разбира се, поради невнимание, но понякога - поради престъпната невъзможност за използване на инструмента.

Източник: www.habr.com

Добавяне на нов коментар