Automatikus adatbázis migráció és eszközei

Előzmények és elképzelések

Nagyszerű cégünkben remekbe szabott szoftvereket építünk, és ez itt nem vicc, hanem reklám :). Mitöbb, azzal szoktuk kecsegtetni ügyfeleinket, hogy a teljes fejlesztési folyamatot nyomon követhetik, nem csak a rendszeres sprint meetingek során, hanem bármikor.

Beletekinthetnek a forráskódba, a ticket nyilvántartó rendszerbe, sőt akár a számukra fenntartott környezetre bármikor egy gombnyomással deploy-olhatják is a legfrissebb verziót. Ez szóról-szóra így is van, azonban egy kis bökkenő mégis van a dologban, aminek orvoslását itt most megpróbálom bemutatni.

Történetesen, ha az adott verzió adatbázis módosítást igényel, akkor az bizony csúnyán belerondít a click&start elképzelésbe. Megpróbáltuk tehát valahogy a build folyamat részeként kezelni a dolgot, és körbenéztünk kész megoldások után. Persze hogy a dolog ennyiben kimerüljön, ahhoz szükséges a megfelelő verzió kezelés is, de ez nem témája a cikknek, valamint ezzel amúgy sem voltak problémáink. A következő elgondolások mentén válogattunk az eszközök között:

  • Képes SQL scripteket értelmezni
    • Upgrade: x => y, ahol y > x
    • Downgrade: y => x, ahol y > x
    • Upgrade és downgrade műveletek batch végrehajtása


  • Képes adatbázis dumpokat értelmezni
    • Adatbázist fel tud építeni
    • Dump és adatbázis összehasonlítása után az eredmény szerint 'cselekszik' (upgrade/downgrade)


  • Képes adatbázisokkal dolgozni
    • Adatbázisok összehasonlítása után az eredmény szerint 'cselekszik' (upgrade/downgrade)


  • Adatbázis gyártók széles körét támogatja
  • Rendelkezik bulid tool (Ant és/vagy Maven) pluginokkal
  • Egyszerű és könnyű használni

Motorháztető alatt

Alapjában véve, mindegyik karbantart egy pillanatképet az adatbázisról, amiben többnyire tételesen le van jegyezve, hogy az eszköz mikor, milyen módosítást végzett az adatbázison, és általában egy-egy ilyen bejegyzés egy-egy adatbázis verziónak felel meg (ha ügyesek vagyunk, akkor az adatbázis és alkalmazás verzióinkat össze tudjuk hangolni). Ezen pillanatképek egy vagy több táblában vannak nyilvántartva, melyek a kezdőállapot inicializálásakor jönnek létre. Kezdőállapot lehet az első verzió, amennyiben az adatbázist már eleve az eszközzel építettük fel, vagy kinevezhetünk egy pillanatnyi állapotot is erre a címre. Ezek után minden egyes művelet végrehajtása egyben metaadat karbantartással is jár, lejegyzésre kerülnek a művelet részletei, illetve verzió állítás is történik. A végrehajtandó műveleteket valamilyen (leíró)nyelven készült fájlok hordozzák, melyeket elnevezési konvenció alapján automatikusan vagy éppen determinisztikusan, megfelelő input után azonosítanak az eszközök.

"Evolúció"

Rövid kutakodás után nyilvánvalóvá vált, hogy bizony lejjebb kell adnunk az elvárásainkból.

Először az automatikus downgrade/rollback ötlete esett áldozatul, melynél egyszerűen koncepcionális problémákba ütközik a gépvezérelt megvalósítás, ugyanis bizonyos módosító scriptekhez (például oszlop típus módosítás) nem generálható rollback script kézi beavatkozás nélkül. (In-memory db-k formájában, pre-, post-dumpok összehasonlítása alapján megoldható lenne a probléma, de ezt még leírni is hosszadalmas, nemhogy megvalósítani). így aztán az eszközök ezt nem, vagy csak korlátozott mértékben támogatják.

Hasonló sorsra jutott az adatbázis dumpok alapján történő migráció gondolata, ki tudja miért ez az eszközök nem nagyon támogatják. (Itt is megoldás lehetne a dumpok in-memory adatbázisként történő kezelése, de a fenti érvelésem sziklaszilárd).

általános konklúzióként elmondhatom, hogy végülis a "Egyszerű és könnyű használni" követelmény szépen alattomosan felülírt minden mást, és elsőszámú elvárássá kűzdötte fel magát. Nem szerettük volna megfizetni a vámon amit megnyertünk a réven, azaz szeretnénk, ha az ügyfél egy gombnyomással nyerne firss verziót, de ez nem kerülne nekünk minden alkalommal nehézkes config műveletekbe.

...és a befutók

Liquibase

A Liquibase talán az egyik "legerősebb" eszköz amivel találkoztunk. A műveleteket úgynevezett changlogokban tartja nyilván, melyek tulajdonképpen xml leíró fájlok. Megfelelől build tool támogatással bír, támogattja a db diff generálást, mi több még a downgrade/rollback műveleteket is. Ez utóbbi esetben ahol tudja, ott legenerája nekünk a műveletet, ellenkező esetben figyelmeztet minket, és kézzel megadhatjuk azt. Hiányosságaként említeném, hogy a különböző sémák közti műveletvégrehajtásokon elvérzik, amennyiben az db constrainteket érint, ezt ugyanis valamiért nem tudja vagy nem kezeli jól (a pillanatnyi verzió). Sajnálatos (véleményem szerint kevés ráfordítással javítható) probléma. A végrehajtandó changelogokat nekünk kell megadnunk neki futtatáskor, ez is sajnálatos, mert állandó beavatkozásért, vagy trükkös megoldásért kiált. összességében véve azért egy erős, jól használható eszköz, bár kissé nehézkes a hatékony de komplikált leírónyelve és a manuális művelet konfiguráció miatt. Kisebb gyakoriságú, de nagy méretű migrációkhoz javasolnám inkább.

Flyway

Nálunk ő nyert. Korántsem bír annyi feature-rel mint fenti társa, cserébe viszont brilliánsan egyszerű, hála főként elnevezési konvenciót követő automatikus megoldásának, amivel a megadott útvonal(akon) található megfelelő nevű fájlok közül mindent végrehajt ami a metaadat nyilvántartása szerint szükséges. Nem támogatja a db diffet, sem a downgrade-et, cserébe ezt megpróbálja megindokolni, több-kevesebb sikerrel. Viszont a műveleteket sql scriptekben kell megadnunk, amit mindenkinek ismert aki adatbázisokkal dolgozik, tehát további könnyebbség. Emiatt továbbá az eszköz ereje megegyezik az sql erejével, tehát nincsenek pl. eltérő sémákból adódó problémák, sem más trükkös megkötések. Amit az sql tud, azt tudja ő is. Támogatja a legfőbb build eszközöket, melyek konfigurációja szintén egyszerű. Remek eszköz gyakran futó apróbb migrációkhoz, de képes kezelni komplexebb dolgokat is.

Konklúzió

Mint kiderült, tökéletes megoldás nincs. Meg kell kötnünk a magunk kompromisszumait, és akkor találunk eszközt a feladatra. Persze ebben a szakmában mindig ott a lehetőség, hogy írjunk egyet magunknak...