Hur man undviker att skjuta sig sjÀlv i foten med Liquibase

Aldrig har det varit sÄ, och nu igen!

I vÄrt senaste projekt bestÀmde vi oss för att anvÀnda Liquibase frÄn början för att undvika problem i framtiden. Det visade sig att inte alla unga medlemmar i teamet vet hur man anvÀnder det pÄ rÀtt sÀtt. Jag hÄll en intern workshop som jag sedan bestÀmde mig för att omvandla till en artikel.

Artikeln innehÄller anvÀndbara tips och en beskrivning av tre av de mest uppenbara fÀllorna man kan gÄ i nÀr man arbetar med verktyg för migrering av relationsdatabaser, sÀrskilt Liquibase. Den Àr avsedd för Java-utvecklare pÄ junior- och mellannivÄ, medan mer erfarna utvecklare kan finna den intressant för att strukturera och repetera sÄdant de troligen redan kÀnner till.

Hur man undviker att skjuta sig sjÀlv i foten med Liquibase

Liquibase och Flyway Àr de tvÄ huvudsakliga konkurrerande teknologierna för att hantera versionering av relationsstrukturer i Java-vÀrlden. Den första Àr helt gratis och brukar praktiskt taget oftare vÀljas för anvÀndning, dÀrför Àr det Liquibase som valts som huvudÀmne för publiceringen. Trots detta kan vissa av de beskrivna praktikerna vara universella beroende pÄ arkitekturen av din applikation.

Migrering av relationsstrukturer har blivit ett nödvÀndigt sÀtt att hantera den svaga flexibiliteten hos relationsdatabaslagring. Under den tid dÄ OOP var populÀrt innebar arbetet med databaser att vi en gÄng beskrev schemat och inte skulle Àndra det igen. Men verkligheten Àr alltid sÄdan att allt förÀndras och förÀndringar i tabellstrukturer krÀvs ganska ofta. Naturligtvis kan sjÀlva processen vara smÀrtsam och obehaglig.

Jag kommer inte att gÄ djupare in pÄ beskrivningen av teknologin och instruktionerna för att lÀgga till biblioteket i ditt projekt, det har redan skrivits tillrÀckligt med artiklar om det:

Dessutom har det redan funnits en utmÀrkt artikel med anvÀndbara tips:

Tips

Jag vill dela med mig av mina tips och kommentarer som föddes genom svett, blod och smÀrta frÄn att lösa migrationsproblem.

1. Innan arbetet pÄbörjas bör man bekanta sig med avsnittet om bÀsta praxis pÄ webbplats Liquibase

DÀr Enkla men viktiga aspekter beskrivs hÀr, utan vilka anvÀndningen av biblioteket kan bli komplicerad. Till exempel, en icke-strukturerad metod för hantering av changsets leder förr eller senare till förvirring och trasiga migrationer. Om man gör beroende förÀndringar av databasstrukturen och tjÀnsternas logik utan att utföra dem samtidigt, ökar risken för att detta resulterar i röda tester eller en trasig miljö. Dessutom innehÄller rekommendationerna för anvÀndning av Liquibase pÄ den officiella webbplatsen ett avsnitt om att utveckla och testa rollback-skript tillsammans med huvud-migreringsskripten. NÄvÀl, i artikeln https://habr.com/ru/post/178665/ finns exempel pÄ kod som rör migrationer och rollback-mekanismen.

2. Om ni har börjat anvĂ€nda migrationsverktyg – tillĂ„t inte manuella Ă€ndringar i databasstrukturen.

Som man sĂ€ger: "En gĂ„ng Persil - alltid Persil". Om er applikationsdatabas har börjat hanteras av Liquibase, leder alla manuella Ă€ndringar omedelbart till ett inkonsekvent tillstĂ„nd, och tilliten till changsets sjunker till noll. Potentiella risker inkluderar timmar av arbete för att Ă„terstĂ€lla databasen, och i vĂ€rsta fall – en kraschad server. Om det finns en DBA-arkitekt i ert team "av den gamla skolan", förklara tĂ„lmodigt och eftertĂ€nksamt hur illa det kan bli om han redigerar databasen efter eget tycke i nĂ„got hypotetiskt SQL Developer.

3. Om changset redan har pushats till repositoriet, undvik att redigera.

Om en annan utvecklare gör en pull och tillĂ€mpar ett changset som senare kommer att redigeras – kommer han definitivt att nĂ€mna dig med vĂ€nliga ord nĂ€r han fĂ„r ett fel vid start av applikationen. Om redigeringen av changset pĂ„ nĂ„got sĂ€tt lĂ€cker in i utvecklingsmiljön – mĂ„ste man navigera den hala vĂ€gen av hotfixar. Problemet handlar om validering av Ă€ndringar via hash-vĂ€rde – den grundlĂ€ggande mekanismen i Liquibase. NĂ€r kod i changset redigeras Ă€ndras hash-vĂ€rdet. Redigering av changsets Ă€r endast möjligt nĂ€r det finns möjlighet att Ă„terstĂ€lla hela databasen frĂ„n början utan datarförlust. I sĂ„dana fall kan refactoring av SQL- eller XML-koden faktiskt underlĂ€tta arbetet och göra migrationer mer lĂ€sbara. Ett exempel kan vara situationen nĂ€r schemat för den ursprungliga databasen godkĂ€ndes inom teamet i början av applikationen.

4. Ha verifierade databackups, om möjligt

HÀr Àr jag sÀker pÄ att allt Àr klart. Om migrationen misslyckas kan allt ÄterstÀllas. I Liquibase finns ett verktyg för att Ängra Àndringar, men skripten för att Ängra behöver ocksÄ skrivas av utvecklaren sjÀlv, och de kan ha lika stora problem som skripten för den ursprungliga förÀndringsuppsÀttningen. Detta innebÀr att det Àr bra att vara förutseende med backup.

5. AnvÀnd verifierade databackups i utvecklingen, om möjligt

Om det inte strider mot avtal och sekretess, om databasen inte innehĂ„ller personuppgifter och inte vĂ€ger som tvĂ„ solar — innan migrationen till levande servrar kan det vara bra att testa hur det fungerar pĂ„ utvecklarens maskin och berĂ€kna nĂ€stan 100% av de potentiella problemen vid migreringen.

6. Kommunicera med andra utvecklare i teamet

I en vĂ€lorganiserad utvecklingsprocess vet alla i teamet vem som gör vad. I verkligheten Ă€r det ofta inte sĂ„, sĂ„ om du gör Ă€ndringar i databasstrukturen inom din uppgift, Ă€r det bra att informera hela teamet om detta. Om nĂ„gon gör Ă€ndringar parallellt — bör du organisera er noggrant. Det Ă€r bra att kommunicera med kollegor Ă€ven efter att jobbet Ă€r klart, inte bara i början. MĂ„nga potentiella problem med förĂ€ndringsuppsĂ€ttningar kan lösas i kodgranskningen.

7. TÀnk pÄ vad du gör!

Det verkar som en sjÀlvklarhet, tillÀmplig i alla situationer. Men mÄnga problem skulle kunnat undvikas om utvecklaren analyserade en gÄng till vad han gör och vilken pÄverkan det kan ha. Att arbeta med migrationer krÀver alltid extra uppmÀrksamhet och noggrannhet.

FĂ€llor

LÄt oss nu se pÄ typiska fÀllor man kan hamna i om man inte följer ovanstÄende rÄd, och vad man egentligen ska göra?

Situation 1. TvÄ utvecklare försöker samtidigt lÀgga till nya förÀndringsuppsÀttningar

Hur man undviker att skjuta sig sjÀlv i foten med Liquibase
Vanya och Petya vill skapa förÀndringsuppsÀttning version 4 utan att veta om varandra. De har gjort Àndringar i databasstrukturen och skickat pull request med olika filer för förÀndringsuppsÀttningen. Följande mekanism föreslÄs:

Hur man löser

  1. PÄ nÄgot sÀtt mÄste kollegorna komma överens om i vilken ordning deras förÀndringsuppsÀttningar ska gÄ, lÄt oss sÀga att Petyas ska tillÀmpas först.
  2. NÄgon mÄste lÀgga till den andra till sig sjÀlv och markera Vasas changset med version 5. Detta kan göras genom Cherry Pick eller en noggrann merge.
  3. Efter Àndringarna bör man alltid kontrollera giltigheten av de utförda ÄtgÀrderna.
    I sjÀlva verket tillÄter Liquibase-mekanismerna att ha tvÄ changsets i version 4 i repositoryn, sÄ det gÄr bra att lÀmna allt som det Àr. Det vill sÀga att ni bara kommer att ha tvÄ förÀndringar av version 4 med olika namn. Med detta tillvÀgagÄngssÀtt blir det mycket svÄrt att navigera i databaskversionerna senare.

Dessutom, precis som hobbitarnas hem, döljer Liquibase mÄnga hemligheter. En av dem Àr nyckeln validCheckSum, som introducerades i version 1.7 och gör det möjligt att ange ett giltigt vÀrde för hash-summan för ett specifikt changset oavsett vad som lagras i databasen. Dokumentationen https://www.liquibase.org/documentation/changeset.html sÀger följande:

LÀgg till en checksumma som anses vara giltig för detta changeSet, oavsett vad som lagras i databasen. AnvÀnds frÀmst nÀr du behöver Àndra ett changeSet och inte vill ha fel pÄ databaser dÀr det redan har körts (inte en rekommenderad procedur)

Ja, ja, en sÄdan procedur rekommenderas inte. Men ibland behÀrskar en mÀktig ljus magiker Àven de mörka teknikerna.

Situation 2. Migration som beror pÄ data

Hur man undviker att skjuta sig sjÀlv i foten med Liquibase

Anta att du inte har möjlighet att anvÀnda sÀkerhetskopior av databaser frÄn aktiva servrar. Petya skapade ett changset, kontrollerade det lokalt och med full sjÀlvsÀkerhet gjorde han en pull request till utvecklingen. Projektledaren kollade för sÀkerhets skull om Petya hade kontrollerat det och sedan fusionerade han. Men deployment pÄ utvecklingsservern misslyckades.

I sjÀlva verket Àr detta möjligt, och ingen Àr skyddad mot det. Detta sker om tabellstrukturerna pÄ nÄgot sÀtt Àr kopplade till specifika data frÄn databasen. Det Àr uppenbart att om Petyas databas bara Àr fylld med testdata, sÄ kan den kanske inte tÀcka alla problematiska fall. Till exempel, vid borttagning av en tabell visar det sig att det finns poster i andra tabeller via Foreign Key som Àr kopplade till poster i den borttagna. Eller vid Àndring av kolumntypen visar det sig att inte 100% av data kan konverteras till den nya typen.

Hur man löser

  • Skriva speciella skript som en gĂ„ng kommer att anvĂ€ndas tillsammans med migreringen för att föra data i rĂ€tt skick. Detta Ă€r en generell vĂ€g för att lösa problemet med att överföra data till nya strukturer efter att migreringarna har utförts, men nĂ„got liknande kan tillĂ€mpas Ă€ven före, i vissa fall. SĂ„dana lösningar Ă€r sjĂ€lvklart inte alltid tillgĂ€ngliga, eftersom att redigera data pĂ„ aktiva servrar kan vara riskabelt och till och med katastrofalt.
  • En annan komplex vĂ€g Ă€r att redigera den befintliga changset. Komplikationen ligger i att alla databaser dĂ€r den har tillĂ€mpats i sin nuvarande form mĂ„ste Ă„terstĂ€llas. Det Ă€r fullt möjligt att hela backend-teamet tvingas lokalt installera databasen frĂ„n grunden.
  • Och den mest universella vĂ€gen Ă€r att flytta problemet med data till utvecklarens miljö genom att Ă„terskapa samma situation och lĂ€gga till en ny changset, före den trasiga, som gör det möjligt att kringgĂ„ problemet.
    Hur man undviker att skjuta sig sjÀlv i foten med Liquibase

Generellt sett, ju mer databasen i frÄga liknar produktionsserverns databaser, desto mindre chans Àr det att migrationsproblem uppstÄr. Och sjÀlvklart, innan man skickar changset till ett repository, bör man tÀnka flera gÄnger pÄ om det kommer att krossa nÄgot.

Situation 3. Liquibase börjar tillÀmpas först efter produktionslanseringen.

Anta att teamledaren har bett Petja att ansluta Liquibase i projektet, men projektet Àr redan i produktion och det finns redan en befintlig databasstruktur.

Problemet Àr sÄledes att pÄ varje nya servrar eller utvecklarmaskiner mÄste de hÀr tabellerna Äterskapas frÄn grunden, medan den redan existerande miljön mÄste förbli i ett konsekvent tillstÄnd, redo att ta emot nya changset.

Hur man löser

HÀr finns ocksÄ flera möjliga vÀgar:

  • Det första och mest uppenbara Ă€r att ha ett separat skript som mĂ„ste tillĂ€mpas manuellt vid initiering av en ny miljö.
  • Det andra, mindre uppenbara, Ă€r att ha en Liquibase-migrering som tillhör en annan Liquibase-kontext och tillĂ€mpa den. Mer information om Liquibase-kontext kan lĂ€sas hĂ€r: https://www.liquibase.org/documentation/contexts.html. Övergripande Ă€r detta en intressant mekanism som kan tillĂ€mpas framgĂ„ngsrikt, till exempel för testning.
  • Den tredje vĂ€gen bestĂ„r av flera steg. Först mĂ„ste en migrering skapas för de redan existerande tabellerna. Sedan mĂ„ste den tillĂ€mpas i en viss miljö för att fĂ„ dess hashvĂ€rde. NĂ€sta steg Ă€r att initiera tomma Liquibase-tabeller pĂ„ vĂ„r icke-tomma server, och i tabellen med historik för tillĂ€mpade changsets kan man manuellt lĂ€gga till en post om ett "som om tillĂ€mpat" changset med redan befintliga förĂ€ndringar i databasen. PĂ„ sĂ„ sĂ€tt börjar historiken pĂ„ den redan existerande servern frĂ„n version 2, och alla nya miljöer kommer att bete sig identiskt.
    Hur man undviker att skjuta sig sjÀlv i foten med Liquibase

Situation 4. Migreringarna blir enorma och hinner inte genomföras

I början av utvecklingen av tjÀnsten anvÀnds oftast Liquibase som ett externt beroende, och alla migreringar hanteras vid appens start. Men med tiden kan du stöta pÄ följande fall:

  • Migreringarna blir enorma och tar lĂ„ng tid att genomföra.
  • Det uppstĂ„r behov av migrering i distribuerade miljöer, till exempel pĂ„ flera instanser av databasservrar samtidigt.
    I sÄdana fall kommer en alltför lÄng tillÀmpning av migreringarna att leda till timeouts vid appens start. Dessutom kan tillÀmpningen av migreringar för varje instans av applikationen separat leda till att olika servrar hamnar i ett osynkroniserat tillstÄnd.

Hur man löser

I sÄdana fall Àr ditt projekt redan stort, kanske till och med vuxet, och Liquibase börjar fungera som ett separat externt verktyg. Anledningen Àr att Liquibase som bibliotek packas i en jar-fil och kan fungera bÄde som beroende inom projektet och autonomt.

I autonomt lÀge kan tillÀmpningen av migreringar lÀggas pÄ din CI/CD-miljö eller pÄ de starka axlarna hos dina systemadministratörer, som Àr specialister pÄ driftsÀttning. För detta behövs kommandoraden för Liquibase. https://www.liquibase.org/documentation/command_line.html. I det lÀget finns möjlighet att starta applikationen först efter att alla nödvÀndiga migreringar har genomförts.

Utdata

Det finns faktiskt mÄnga fler fÀllor nÀr man arbetar med databasmigreringar, och mÄnga av dem krÀver ett kreativt tillvÀgagÄngssÀtt. Det Àr viktigt att förstÄ att om verktyget anvÀnds korrekt, sÄ kan de flesta av dessa fÀllor undvikas. Personligen har jag i olika former stött pÄ alla nÀmnda problem, och vissa av dem har varit ett resultat av mina egna misstag. Oftast hÀnder detta pÄ grund av oförsiktighet, men ibland pÄ grund av en kriminell oförmÄga att anvÀnda verktyget.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster