Hoe je jezelf niet in de voet schiet met Liquibase

Nooit eerder gebeurd, en nu weer!

In een recent project besloten we om Liquibase vanaf het begin te gebruiken om toekomstige problemen te vermijden. Het bleek dat niet alle jonge teamleden weten hoe ze het op de juiste manier moeten gebruiken. Ik heb een interne workshop gehouden, die ik daarna besloot om te transformeren in een artikel.

Het artikel bevat nuttige tips en beschrijft drie van de meest opvallende valkuilen waarin je kunt trappen bij het werken met migratietools voor relationele databases, met name Liquibase. Het is bedoeld voor Java-ontwikkelaars van niveau Junior en Middle; voor meer ervaren ontwikkelaars kan het interessant zijn voor het structureren en herhalen van dingen die ze waarschijnlijk al weten.

Hoe je jezelf niet in de voet schiet met Liquibase

Liquibase en Flyway zijn de belangrijkste concurrerende technologieƫn voor het beheersen van versies van relationele structuren in de Java-wereld. De eerste is volledig gratis en wordt in de praktijk vaker gekozen. Daarom is Liquibase de held van deze publicatie. Sommige van de beschreven praktijken kunnen echter universeel zijn, afhankelijk van de architectuur van je toepassing.

Migraties van relationele structuren zijn een onvermijdelijke manier geworden om de zwakke flexibiliteit van relationele gegevensopslag te bestrijden. In het tijdperk van de mode voor OOP was de werkstijl met databases dat we de schema eenmaal beschreven en deze niet meer zouden aanraken. Maar de realiteit is altijd dat alles verandert, en wijzigingen in de tabelstructuren zijn vrij regelmatig vereist. Uiteraard kan het proces zelf pijnlijk en onaangenaam zijn.

Ik zal niet dieper ingaan op de technologie en instructies voor het toevoegen van de bibliotheek aan je project, hierover zijn al genoeg artikelen geschreven:

Bovendien was er al een geweldig artikel met nuttige tips:

Tips

Ik wil mijn tips en opmerkingen delen die zijn ontstaan door het zweet, bloed en de pijn van het oplossen van migratieproblemen.

1. Voordat je begint, moet je de sectie met beste praktijken doornemen. website Liquibase

Daar worden eenvoudige, maar zeer belangrijke dingen beschreven, zonder welke het gebruik van de bibliotheek uw leven kan compliceren. Bijvoorbeeld, een ongestructureerde aanpak van het beheer van changelogs zal vroeg of laat leiden tot verwarring en kapotte migraties. Als u afhankelijk van elkaar zijnde wijzigingen in de database-structuur en service-logica niet gelijktijdig uitrolt, is de kans groot dat dit leidt tot rode tests of een kapotte omgeving. Bovendien bevat de officiƫle site aanbevelingen voor het gebruik van Liquibase, waaronder het ontwikkelen en controleren van rollback-scripts samen met de belangrijkste migratiescripts. En in het artikel https://habr.com/ru/post/178665/ zijn er codevoorbeelden met betrekking tot migraties en rollback-mechanismen.

2. Als u migratietools bent gaan gebruiken, vermijd dan handmatige aanpassingen in de database-structuur.

Zoals men zegt: "Een keer Persil — altijd Persil". Als de database van uw toepassing wordt beheerd door Liquibase, leiden handmatige wijzigingen onmiddellijk tot een inconsistente staat, en het vertrouwen in de changelogs daalt naar nul. PotentiĆ«le risico's zijn enkele uren verloren gaan aan het herstellen van de database, en in het slechtste geval een kapotte server. Als er een DBA Architect van de 'oude stempel' in uw team is, leg hem geduldig en doordacht uit hoe slecht het zal gaan als hij de database op zijn eigen inzicht aanpast vanuit een hypothetische SQL Developer.

3. Als een changelog al in de repository is gepusht, vermijd dan editing.

Als een andere ontwikkelaar een pull heeft gedaan en de changelog heeft toegepast die later wordt bewerkt, zal hij u zeker met goede woorden herinneren wanneer hij een fout krijgt bij het starten van de applicatie. Als de editing van de changelog op de een of andere manier doorlekt naar de development, zal het noodzakelijk zijn om de gladde weg van hotfixes te bewandelen. De kern van het probleem draait om de validatie van wijzigingen op basis van hash-sommen — het belangrijkste mechanisme van Liquibase. Bij het bewerken van de changelog-code verandert de hash-som. Het bewerken van changelogs is alleen mogelijk wanneer het mogelijk is om de hele database opnieuw zonder gegevensverlies te implementeren. In dat geval kan het refactoren van SQL of XML-code, integendeel, het leven vergemakkelijken en de migraties leesbaarder maken. Een voorbeeld kan zijn dat de structuur van de oorspronkelijke database bij de start van de applicatie binnen het team werd afgestemd.

4. Zorg voor betrouwbare databaseback-ups, indien mogelijk

Hier is alles wel duidelijk. In het geval dat de migratie niet goed gaat, kan alles worden teruggezet. In Liquibase is er een rollback-tool, maar de scripts voor rollback worden ook door de ontwikkelaar geschreven, en daarin kunnen net zoveel problemen optreden als in de scripts van de hoofdchangeset. Dit betekent dat het altijd nuttig is om backups te hebben.

5. Gebruik betrouwbare databaseback-ups in de ontwikkeling, indien mogelijk

Als dit niet in strijd is met de contracten en privacy, er geen persoonsgegevens in de database staan en deze niet zo zwaar is als twee zonnen — voordat migraties op live servers worden toegepast, kun je controleren hoe het werkt op de machine van de ontwikkelaar en vrijwel 100% van de potentiĆ«le problemen bij de migratie berekenen.

6. Communiceer met andere ontwikkelaars in het team

In een goed georganiseerde ontwikkelprocedure weten alle teamleden wie waarmee bezig is. In de praktijk is dit vaak niet het geval, dus als je veranderingen in de database-structuur voorbereidt, is het aan te raden om het hele team hier extra van op de hoogte te stellen. Als iemand parallel wijzigingen aanbrengt, moet je voorzichtig te werk gaan. Praat ook met collega's na de afronding van het werk, niet alleen aan het begin. Veel potentiƫle problemen met changesets kunnen in de fase van code review worden opgelost.

7. Denk na over wat je doet!

Het lijkt een voor de hand liggend advies, toepasbaar op elke situatie. Veel problemen hadden echter kunnen worden voorkomen als de ontwikkelaar nog eens had nagedacht over wat hij doet en wat de invloed daarvan kan zijn. Werken met migraties vereist altijd extra aandacht en voorzichtigheid.

Valstrikken

Laten we nu de typische valstrikken bekijken waarin je kunt belanden als je de bovenstaande adviezen niet opvolgt, en wat je in feite moet doen?

Situatie 1. Twee ontwikkelaars proberen tegelijkertijd nieuwe changesets toe te voegen

Hoe je jezelf niet in de voet schiet met Liquibase
Vasya en Petya willen een changeset versie 4 maken, zonder van elkaar te weten. Ze hebben wijzigingen in de database-structuur aangebracht en een pull request ingediend, met verschillende changeset-bestanden. Vervolgens wordt de volgende actie voorgesteld:

Hoe op te lossen

  1. Collega's moeten op de een of andere manier overeenkomen in welke volgorde hun changesets moeten komen, laten we zeggen dat Petya's als eerste moet worden toegepast.
  2. Iemand moet de tweede naar zichzelf verplaatsen en de changset van Vasya markeren met versie 5. Dit kan gedaan worden via Cherry Pick of een zorgvuldige merge.
  3. Na de wijzigingen is het noodzakelijk om de validiteit van de uitgevoerde acties te controleren.
    Eigenlijk zullen de mechanismen van Liquibase ervoor zorgen dat er twee changsets van versie 4 in de repository zijn, dus je kunt alles laten zoals het is. Dit betekent dat er simpelweg twee wijzigingen van versie 4 met verschillende namen zijn. Bij deze benadering wordt het later in de versies van de database erg moeilijk om je te oriƫnteren.

Bovendien, net als het huis van hobbits, bevat Liquibase veel geheimen. Een daarvan is de sleutel validCheckSum, die is geĆÆntroduceerd met versie 1.7 en waarmee je een geldige waarde voor de hash-sum voor een bepaald changset kunt opgeven, ongeacht wat er in de database is opgeslagen. Documentatie https://www.liquibase.org/documentation/changeset.html zegt het volgende:

Voeg een checksum toe die als geldig wordt beschouwd voor dit changeSet, ongeacht wat er in de database staat. Hoofdzakelijk gebruikt wanneer je een changeSet moet wijzigen en geen fouten wilt krijgen op databases waar het al is uitgevoerd (niet aanbevolen procedure)

Ja, ja, deze procedure wordt niet aanbevolen. Maar soms beheerst een sterke lichte tovenaar ook donkere technieken.

Situatie 2. Migratie die afhankelijk is van gegevens.

Hoe je jezelf niet in de voet schiet met Liquibase

Stel dat je geen mogelijkheid hebt om back-ups van databases van live servers te gebruiken. Petya heeft een changset gemaakt, dit lokaal gecontroleerd en met volledige zekerheid van zijn gelijk heeft hij een pull request gedaan naar de dev-omgeving. De projectleider vroeg voor de zekerheid of Petya dit had gecontroleerd en daarna heeft hij het samengevoegd. Maar de uitrol op de dev-server is mislukt.

In werkelijkheid is dit mogelijk, en niemand is hiervoor verzekerd. Dit gebeurt wanneer wijzigingen in de tabellenstructuur op de een of andere manier verbonden zijn aan specifieke gegevens uit de database. Het is duidelijk dat als Petya's database alleen met testgegevens is gevuld, deze mogelijk niet alle probleemgevallen dekt. Bijvoorbeeld, bij het verwijderen van een tabel blijkt dat er records in andere tabellen zijn via Foreign Key die gekoppeld zijn aan records in de verwijderde tabel. Of bij het wijzigen van het type kolom blijkt dat niet 100% van de gegevens naar het nieuwe type kan worden geconverteerd.

Hoe op te lossen

  • Schrijf speciale scripts die ƩƩnmalig samen met de migratie zullen worden toegepast en de gegevens in de juiste staat zullen brengen. Dit is een algemene oplossing voor het probleem van het overdragen van gegevens naar nieuwe structuren, zelfs na het toepassen van migraties, maar iets dergelijks kan in bepaalde gevallen ook vóór de migratie worden toegepast. Deze aanpak is natuurlijk niet altijd beschikbaar, omdat het bewerken van gegevens op live servers gevaarlijk en zelfs vernietigend kan zijn.
  • Een andere complexe weg is het bewerken van de bestaande changset. De moeilijkheid is dat alle databases waar deze changset al in zijn huidige vorm is toegepast, moeten worden hersteld. Het is heel goed mogelijk dat het hele backendteam gedwongen zal zijn om de database lokaal vanaf nul op te zetten.
  • En de meest universele manier is om het probleem met de gegevens over te brengen naar de ontwikkelaarsomgeving, waarbij dezelfde situatie wordt gerecreĆ«erd en een nieuwe changset wordt toegevoegd tot de gebroken changset, waarmee het probleem kan worden omzeild.
    Hoe je jezelf niet in de voet schiet met Liquibase

In het algemeen geldt: hoe meer de database qua gegevensstructuur lijkt op de database van de productie server, hoe kleiner de kans dat migratieproblemen zich ver buiten de perken zullen manifesteren. En natuurlijk, voordat je de changset naar de repository stuurt, zou je een paar keer moeten nadenken over de vraag of het iets zal breken.

Situatie 3. Liquibase begint te worden toegepast na de productie-uitvoering.

Stel dat de teamleider Petya vraagt om Liquibase aan het project toe te voegen, maar het project al in productie is en er al een bestaande database-structuur is.

Daarom is het probleem dat op alle nieuwe servers of machines van ontwikkelaars de gegevens van deze tabellen vanaf nul moeten worden gerecreƫerd, terwijl de al bestaande omgeving in een consistente staat moet blijven om nieuwe changsets te kunnen accepteren.

Hoe op te lossen

Er zijn ook verschillende manieren hiervoor:

  • De eerste en meest voor de hand liggende manier is om een aparte script te hebben dat handmatig moet worden toegepast bij de initiatie van een nieuwe omgeving.
  • De tweede, minder voor de hand liggende manier is om een Liquibase-migratie te hebben die zich in een andere Liquibase-context bevindt en deze toe te passen. Meer over Liquibase-context kun je hier lezen: https://www.liquibase.org/documentation/contexts.html. Over het algemeen is dit een interessant mechanisme dat met succes kan worden toegepast, bijvoorbeeld voor testen.
  • De derde weg bestaat uit verschillende stappen. Eerst moet er een migratie worden gemaakt voor de al bestaande tabellen. Vervolgens moet deze worden toegepast in een bepaalde omgeving, zodat de hashwaarde kan worden verkregen. De volgende stap is het initiĆ«ren van een lege Liquibase-tabellen op onze niet-lege server, en in de geschiedenis van de toepassing van changeSets kan handmatig een record worden geplaatst van een ā€˜alsof toegepaste’ changeSet met al aanwezige wijzigingen in de database. Zo begint de geschiedenis op de reeds bestaande server vanaf versie 2, en zullen alle nieuwe omgevingen zich identiek gedragen.
    Hoe je jezelf niet in de voet schiet met Liquibase

Situatie 4. Migraties worden enorm en kunnen niet snel genoeg worden uitgevoerd.

Aan het begin van de ontwikkeling van de service wordt Liquibase doorgaans als externe afhankelijkheid gebruikt, en worden alle migraties behandeld bij de opstart van de applicatie. Maar na verloop van tijd kunt u de volgende situaties tegenkomen:

  • Migraties worden enorm en nemen veel tijd in beslag.
  • Er ontstaat de noodzaak voor migraties in gedistribueerde omgevingen, bijvoorbeeld op meerdere instanties van databaseserver tegelijk.
    In dat geval kan het te lang duren om migraties toe te passen, wat leidt tot time-outs bij het opstarten van de applicatie. Bovendien kan het apart toepassen van migraties voor elke instantie van de applicatie ertoe leiden dat verschillende servers in een niet-synchrone staat verkeren.

Hoe op te lossen

In dergelijke gevallen is uw project al groot, misschien zelfs volwassen, en begint Liquibase te fungeren als een apart extern hulpmiddel. Het punt is dat Liquibase als bibliotheek wordt samengevoegd in een jar-bestand en kan functioneren als een afhankelijkheid binnen het project, of autonoom.

In autonome modus kan de toepassing van migraties worden toevertrouwd aan uw CI/CD-omgeving of aan de sterke schouders van uw systeembeheerders of implementatiespecialisten. Hiervoor is de commandoregel van Liquibase vereist. https://www.liquibase.org/documentation/command_line.html. In deze modus is het mogelijk om de toepassing al te starten zodra alle vereiste migraties zijn uitgevoerd.

Uitslag

Er zijn in werkelijkheid veel meer valkuilen bij het werken met database-migraties, en veel daarvan vereisen een creatieve aanpak. Het is belangrijk te begrijpen dat als je het hulpmiddel juist gebruikt, de meeste van deze valkuilen te vermijden zijn. Persoonlijk heb ik in verschillende vormen met al deze problemen te maken gehad, en sommige daarvan waren het resultaat van mijn eigen fouten. Dit gebeurt meestal door onoplettendheid, maar soms ook door gebrek aan vaardigheden in het gebruik van het hulpmiddel.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster