Cum să nu te împuști în picior folosind Liquibase

Niciodată nu a fost, și iată că din nou!

În cadrul unui nou proiect, am decis să folosim Liquibase de la început, pentru a evita problemele în viitor. Așa cum s-a dovedit, nu toți membrii tineri ai echipei știu cum să-l folosească corect. Am organizat un workshop intern, pe care ulterior am decis să-l transform într-un articol.

Articolul include sfaturi utile și descrierea celor trei capcane evidente în care se poate cădea lucrând cu instrumentele de migrare a bazelor de date relaționale, în special Liquibase. Este destinat dezvoltatorilor Java de nivel Junior și Middle; pentru dezvoltatorii mai experimentați, poate fi interesant pentru structurarea și revizuirea a ceea ce, cel mai probabil, le este deja cunoscut.

Cum să nu te împuști în picior folosind Liquibase

Liquibase și Flyway sunt principalele tehnologii concurente pentru gestionarea versiunilor structurilor relaționale în lumea Java. Prima este complet gratuită și, în practică, este aleasă mai des pentru utilizare, de aceea Liquibase a fost ales ca erou al publicației. Cu toate acestea, unele dintre practicile descrise pot fi universale, în funcție de arhitectura aplicației dumneavoastră.

Migrarea structurilor relaționale este o metodă apărută din necesitate pentru a combate rigiditatea scăzută a bazelor de date relaționale. În epoca în care OOP era la modă, stilul de lucru cu baza de date presupunea că descriem o dată schema și nu o vom mai modifica. Dar realitatea este că totul se schimbă, iar modificările structurii tabelului sunt necesare destul de frecvent. Evident, procesul în sine poate fi dureros și neplăcut.

Nu voi aprofunda descrierea tehnologiei și instrucțiunile pentru adăugarea bibliotecii în proiectul dumneavoastră, pe acest subiect au fost scrise suficiente articole:

În plus, a fost deja un articol excelent despre sfaturi utile:

Sfaturi

Vreau să împărtășesc sfaturile și comentariile mele, care s-au născut prin sudoare, sânge și durerea de a rezolva problemele de migrare.

1. Înainte de a începe, ar trebui să te familiarizezi cu secțiunea celor mai bune practici de pe site Liquibase

Acolo Sunt descrise lucruri simple, dar foarte importante, fără de care utilizarea bibliotecii vă poate complica viața. De exemplu, o abordare nestructurată în gestionarea changelist-urilor va duce mai devreme sau mai târziu la confuzie și migrații defectuoase. Dacă modificările care depind una de alta în structura bazei de date și logica serviciilor nu sunt implementate simultan, există o probabilitate mare ca acest lucru să conducă la teste eșuate sau la un mediu defect. În plus, recomandările privind utilizarea Liquibase de pe site-ul oficial conțin un punct referitor la dezvoltarea și verificarea scripturilor de rollback împreună cu scripturile principale de migrare. Și în articol https://habr.com/ru/post/178665/ sunt exemple de cod referitoare la migrații și mecanismul de rollback.

2. Dacă ați început să utilizați instrumente de migrație, nu permiteți modificări manuale în structura bazei de date.

Cum se spune: „Odată Persil — întotdeauna Persil”. Dacă baza de date a aplicației voastre a început să fie gestionată de Liquibase — orice modificări manuale vor conduce instantaneu la un statut inconsistent, iar nivelul de încredere în changelist-uri devine zero. Riscurile pot include câteva ore pierdute pentru recuperarea bazei de date, iar în cel mai rău caz — un server distrus. Dacă în echipa voastră există un DBA Architect „de veche școală”, explicați-i cu răbdare și atenție cât de rău va fi dacă va edita baza de date după bunul său plac dintr-un presupus SQL Developer.

3. Dacă changelist-ul a fost deja pus în repo, evitați modificările.

Dacă un alt dezvoltator a făcut pull și a aplicat changelist-ul, care ulterior va fi editat, el vă va menționa cu siguranță cu un cuvânt bun atunci când va primi o eroare la pornirea aplicației. Dacă modificarea changelist-ului cumva ajunge în mediu de dezvoltare — va trebui să parcurgereți un drum al hotfix-urilor. Problema esențială este legată de validarea modificărilor prin sumă de verificare — mecanismul principal al Liquibase. Când se editează codul changelist-ului, suma de verificare se schimbă. Modificările changelist-urilor sunt posibile doar atunci când există posibilitatea de a desfășura toată baza de date de la zero fără pierderi de date. În acest caz, refactorizarea codului SQL sau XML poate, dimpotrivă, să facă migrațiile mai ușor de citit. Un exemplu poate fi situația în care, la începutul aplicației, schema bazei de date inițiale a fost convenită în cadrul echipei.

4. Asigură-te că ai copii de siguranță verificate ale bazelor de date, dacă este posibil

Aici, cred că totul este clar. În cazul în care migrarea a avut loc eșuat, totul poate fi restabilit. În Liquibase există un instrument pentru revenirea modificărilor, dar scripturile pentru revenire sunt scrise de asemenea de dezvoltator, iar în ele pot apărea probleme cu aceeași probabilitate ca și în scripturile setului de schimbări inițial. Acest lucru înseamnă că este util să te protejezi cu copii de siguranță în orice caz.

5. Folosește copii de siguranță verificate ale bazelor de date în dezvoltare, dacă este posibil

Dacă acest lucru nu contravine contractelor și politicii de confidențialitate, în baza nu sunt date personale, și nu este mai grea decât două soare — înainte de aplicarea migrațiilor pe servere active, poți verifica cum va funcționa pe mașina dezvoltatorului și poți identifica aproape 100% din problemele potențiale ce pot apărea în timpul migrației.

6. Comunică cu alți dezvoltatori din echipă

Într-un proces de dezvoltare bine organizat, toți din echipă știu cine este ocupat cu ce. În realitate, adesea nu este așa, așa că, dacă în cadrul sarcinii tale pregătești modificări ale structurii bazei de date, este de preferat să informezi suplimentar întreaga echipă despre acest lucru. Dacă cineva face modificări în paralel, ar trebui să vă organizați cu grijă. Este important să comunici și după finalizarea lucrării, nu doar la început. Multe probleme potențiale cu seturile de schimbări pot fi rezolvate în etapa de revizuire a codului.

7. Gândește-te la ceea ce faci!

De parcă ar fi un sfat evident, aplicabil în orice situație. Cu toate acestea, multe probleme ar putea fi evitate dacă dezvoltatorul ar analiza încă o dată ce face și la ce ar putea afecta. Lucrul cu migrațiile necesită întotdeauna o atenție suplimentară și precauție.

Capcane

Acum să analizăm capcanele tipice în care poți cădea dacă nu urmezi recomandările de mai sus, și ce ar trebui să faci de fapt?

Situația 1. Doi dezvoltatori încearcă să adauge simultan seturi de schimbări noi

Cum să nu te împuști în picior folosind Liquibase
Vasia și Petia doresc să creeze un set de schimbări pentru versiunea 4, fără să știe unul despre altul. Au efectuat modificări în structura bazei de date și au trimis un pull request, cu fișiere diferite de seturi de schimbări. Se propune următorul mecanism de acțiune:

Cum să rezolvi

  1. Cumva, colegii trebuie să se pună de acord cu privire la ordinea în care trebuie să vină seturile lor de schimbări, să presupunem că setul lui Petia trebuie aplicat primul.
  2. Cineva trebuie să adauge al doilea element și să marcheze changset-ul lui Vasia cu versiunea 5. Aceasta poate fi realizată prin Cherry Pick sau un merge atent.
  3. După modificări, este esențial să verificați validitatea acțiunilor efectuate.
    De fapt, mecanismele Liquibase permit să existe în repository două changset-uri de versiune 4, astfel încât le puteți lăsa pe toate așa cum sunt. Adică veți avea pur și simplu două modificări pentru versiunea 4 cu denumiri diferite. În această abordare, devine foarte complicat să navigați prin versiunile bazei de date ulterior.

În plus, Liquibase, ca și casa hobbiților, ascunde multe secrete. Unul dintre acestea este cheia validCheckSum, care a apărut cu versiunea 1.7 și permite specificarea unei valori valide a hash-ului pentru un anumit changset, indiferent de ceea ce este stocat în baza de date. Documentația https://www.liquibase.org/documentation/changeset.html spune următoarele:

Adaugă un checksum considerat valid pentru acest changeSet, indiferent de ceea ce este stocat în baza de date. Se folosește în principal atunci când trebuie să schimbi un changeSet și nu vrei să apară erori pe bazele de date pe care a rulat deja (nu este o procedură recomandată)

Da, da, o astfel de procedură nu este recomandată. Dar uneori un vrăjitor puternic și luminos stăpânește și tehnici întunecate.

Situația 2. Migrarea care depinde de date.

Cum să nu te împuști în picior folosind Liquibase

Presupunând că nu aveți posibilitatea de a utiliza backup-uri ale bazelor de date de pe serverele live. Petya a creat un changset, l-a verificat local și cu o încredere totală în corectitudinea sa a făcut un pull request în dezvoltare. Liderul proiectului, de precauție, a întrebat dacă Petya l-a verificat, și apoi l-a integrat. Dar desfășurarea pe serverul de dezvoltare a picat.

De fapt, așa ceva este posibil, și nimeni nu este protejat de acest lucru. Se întâmplă atunci când modificările structurii tabelelor sunt somehow legate de datele specifice din baza de date. Este evident că, dacă baza lui Petya este umplută doar cu date de test, aceasta poate să nu acopere toate cazurile problematice. De exemplu, atunci când se șterge o tabelă, se descoperă că există înregistrări în alte tabele prin Foreign Key, legate de înregistrările din tabelă. Sau, când se schimbă tipul unei coloane, se dovedește că nu 100% din date pot fi transformate în noul tip.

Cum să rezolvi

  • Scrieți scripturi speciale care vor fi aplicate o singură dată împreună cu migrarea și vor aduce datele în formă corespunzătoare. Aceasta este o abordare generală pentru a rezolva problema transferului de date în noi structuri deja după aplicarea migrațiilor, dar ceva similar poate fi aplicat și înainte, în cazuri particulare. Această alegere, desigur, nu este întotdeauna disponibilă, deoarece editarea datelor pe servere active poate fi periculoasă și chiar devastatoare.
  • O altă cale complicată este de a modifica changsetul existent. Dificultatea constă în faptul că toate bazele de date unde acesta a fost deja aplicat în forma sa actuală trebuie restaurate. Este foarte posibil ca întreaga echipă de backend să fie nevoită să reîncărcați local baza de date de la zero.
  • Cea mai universală abordare este să se mute problema datelor în mediul dezvoltatorului, recreând aceeași situație și adăugând un nou changset, înainte de cel defect, care va permite ocolirea problemei.
    Cum să nu te împuști în picior folosind Liquibase

În general, cu cât baza de date se aseamănă mai bine cu baza serverului de producție, cu atât mai puțin este riscul ca problemele cu migrațiile să fie de amploare. Și, desigur, înainte de a trimite changsetul în repository, merită să te gândești de câteva ori dacă nu va strica ceva.

Situația 3. Liquibase începe să fie aplicat după ce a fost lansat în producție.

Să presupunem că team leader-ul i-a cerut lui Petya să integreze Liquibase în proiect, însă proiectul este deja în producție și există deja o structură de bază existentă.

Prin urmare, problema constă în faptul că pe orice noi servere sau mașini ale dezvoltatorilor, datele acestor tabele trebuie recreate de la zero, iar mediul existent trebuie să rămână într-o stare consistentă, pregătită să accepte noile changsets.

Cum să rezolvi

Există și aici mai multe opțiuni:

  • Prima și cea mai evidentă este de a avea un script separat, care trebuie aplicat manual la inițializarea noii medii.
  • A doua opțiune — mai puțin evidentă, este de a avea o migrație Liquibase care se află într-un alt Context Liquibase și de a o aplica. Mai multe informații despre Contextul Liquibase pot fi citite aici: https://www.liquibase.org/documentation/contexts.html. În general, acesta este un mecanism interesant, care poate fi aplicat cu succes, de exemplu, pentru testare.
  • A treia cale constă din mai mulți pași. Mai întâi, trebuie creată o migrație pentru tabelele deja existente. Apoi, aceasta trebuie aplicată pe un anumit mediu, iar astfel va fi obținută suma hash. Următorul pas este să inițializăm tabelele Liquibase goale pe serverul nostru care nu este gol, iar în tabelul cu istoricul aplicării changelog-urilor, putem adăuga manual o înregistrare despre un changelog „aplicat” cu modificările deja existente în bază. Astfel, pe serverul deja existent, numărătoarea istoricului va începe de la versiunea 2, iar toate noile medii se vor comporta identic.
    Cum să nu te împuști în picior folosind Liquibase

Situația 4. Migrațiile devin uriașe și nu reușesc să fie executate la timp.

La începutul dezvoltării serviciului, de obicei, Liquibase este folosit ca o dependență externă, iar toate migrațiile sunt procesate la pornirea aplicației. Cu toate acestea, în timp, s-ar putea să te confrunți cu următoarele cazuri:

  • Migrațiile devin uriașe și durează mult timp pentru a fi executate.
  • Apare necesitatea migrației în medii distribuite, de exemplu, pe mai multe instanțe ale serverelor de baze de date simultan.
    În acest caz, aplicarea prea lentă a migrațiilor va duce la timeout-uri la pornirea aplicației. În plus, aplicarea migrațiilor pentru fiecare instanță a aplicației separat poate duce la faptul că diferite servere vor ajunge să fie în stare nesincronizată.

Cum să rezolvi

În astfel de cazuri, proiectul tău este deja mare, poate chiar matur, și Liquibase începe să funcționeze ca un instrument extern distinct. Problema este că Liquibase, ca bibliotecă, este compilată într-un fișier jar și poate funcționa atât ca o dependență în interiorul proiectului, cât și autonom.

În modul autonom, poți lăsa aplicația migrațiilor pe mediu CI/CD sau pe umerii puternici ai administratorilor de sistem specializați în implementare. Pentru aceasta, va fi nevoie de linia de comandă Liquibase. https://www.liquibase.org/documentation/command_line.htmlÎn acest mod, există posibilitatea de a lansa aplicația după ce toate migrațiile necesare au fost efectuate.

Ieșire

În realitate, capcanele în lucrul cu migrarea bazelor de date pot fi mult mai numeroase, iar multe dintre ele necesită o abordare creativă. Este important să înțelegem că, dacă folosim corect instrumentul, majoritatea acestor capcane pot fi evitate. Personal, am întâlnit diferite forme ale tuturor problemelor menționate, iar unele dintre ele au fost rezultatul greșelilor mele. De obicei, aceste situații apar din neatenție, dar uneori – dintr-o incapacitate flagrantă de a folosi instrumentul.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster