Automatizacija migracija baze podataka

Automatizacija migracija baze podataka znači da se izmjene šeme sa laptopa programera do produkcije kreću kao pregledane, ponovljive skripte, a ne kao SQL konzola otvorena na živom serveru. Narudžbe, korisnici i plaćanja zavise od oblika tabela. Kolona dodata ručno, zaboravljen indeks ili backfill koji zaključa tabelu checkouta malu izmjenu pretvaraju u prekid rada i bazu koju niko ne može ponovo izgraditi.

U CodeWizu šemu i izmjene podataka stavljamo pod kontrolu verzija za Laravel, Node.js, WordPress i obične SQL sisteme. Pišemo skripte, uključujemo ih u CI/CD, odvajamo sigurne strukturne korake od teških backfillova i ostavljamo put za rollback koji je stvarno isproban. PostgreSQL i MySQL su uobičajeni enginei; ista disciplina važi i kada se sa kodom moraju pomjeriti MongoDB indeksi ili šema pretrage.

Usluga je za timove čija je produkcijska baza odlutala od repozitorijuma, za proizvode koji kolone dodaju pod saobraćajem i za kompanije koje žele da se svako okruženje – lokalno, staging, produkcija – gradi iz istih fajlova. Ako release i dalje uključuje nekoga ko SQL pokreće iz tiketa, automatizacija je rješenje.

Migracija: Žuti saobraćajni znak sa strelicama u dva smjera usred pustinje

Automatizacija migracija baze podataka uz sigurne skripte

Migraciona skripta je mala, poredana izmjena: dodati kolonu, napraviti indeks, popuniti vrijednost, dodati ograničenje. Primijenjene redom, skripte ponovo grade šemu od prazne baze ili postojeću bazu dovode do verzije koju kod očekuje. Tabela evidencije (schema_migrations, flyway_schema_history ili Laravel tabela migrations) pamti šta je već odrađeno, pa deploy istu izmjenu ne primijeni dvaput i nijednu ne preskoči.

Skripte pišemo tako da ih je sigurno pregledati i pokrenuti pod saobraćajem:

  • Jedna logička izmjena po fajlu, imenovana tako da je redoslijed očit i stabilan.
  • Fajl koji je prošao na produkciji više se ne mijenja. Sljedeća izmjena je novi fajl.
  • Strukturne izmjene ostaju odvojene od backfilla podataka. Update od deset miliona redova ne skriva se u istom koraku kao ADD COLUMN.
  • Lockove biramo namjerno. PostgreSQL dobija CREATE INDEX CONCURRENTLY i ograničenja dodata kao NOT VALID prije validacije. MySQL dobija online DDL, ili gh-ost / pt-online-schema-change kada je kopija sigurnija.
  • Skripta je idempotentna gdje engine to dozvoljava, a glasno pada tamo gdje ne dozvoljava.

Šta dobijate

  • Folder migracija u repozitorijumu aplikacije, sa kratkim komentarom uz sve što zaključava ili prepisuje tabelu.
  • CI posao koji ih primijeni na bazu za jednokratnu upotrebu i obori build ako ne prođu.
  • Runbook: ko primjenjuje migracije, kojim redom u odnosu na deploy aplikacije i šta raditi ako jedna padne.

Kontrola verzija za svaku izmjenu šeme

Kontrola verzija čini šemu obnovljivom. Fajlovi migracija žive u Gitu pored koda koji ih traži, u istom pull requestu. Recenzent vidi kolonu, indeks i izmjenu upita zajedno. Produkcija više nije posebna kopija koju zna ponovo složiti samo jedna osoba.

Bijela strelica nacrtana na asfaltu koja pokazuje nazad ulijevo

Da grane i okruženja ostanu iskrena

  • Vremenske oznake ili jedan niz, plus pravilo za sudar brojeva kada dvije grane dodaju migraciju. Radije uzimamo vremenske oznake i CI provjeru koja odbija duplikate.
  • Isti fajlovi se primjenjuju na svakom okruženju. Staging nije mjesto gdje neko „samo proba” iskaz koji nikada ne uđe u Git.
  • Postojeća baza dobija baseline: trenutnu šemu uzimamo kao početnu tačku, označimo je primijenjenom i samo nove izmjene su skripte. Ne pretvaramo se da je pet godina stara produkcijska baza građena od prazne.
  • Seedovi i referentni podaci bez kojih aplikacija ne radi (valute, uloge, planovi) također su verzionisani, odvojeno od glomaznih test podataka.

Redoslijed deploya je dio dogovora. Kod proširujuće izmjene migracija ide prije novog koda. Kod uklanjanja ide nakon što stari kod nestane. To uparivanje je srž releasea bez prekida i pripada pipelineu, a ne poruci u chatu. Isto razmišljanje o pipelineu vidimo i u tome kako radimo deployment na DigitalOceanu, AWS-u, Hetzneru i bare metalu.

Strategije rollbacka koje možete uvježbati

Down migracija nije čarobno poništavanje. DROP COLUMN uništava vrijednosti, a down skripta pisana mjesecima kasnije često ne odgovara onome što produkcija zaista sadrži. Rollback tretiramo kao izbor, donesen za svaku izmjenu, i uvježbavamo ga.

Instrumenti u kokpitu aviona osvijetljeni zalaskom sunca prije polijetanja
  • Popravka unaprijed. Ako je novi kod pogrešan, a kolona bezopasna, šaljemo novu migraciju ili vraćamo kod. To je podrazumijevano za proširujuće izmjene.
  • Rollback koda uz proširenu šemu. Stara i nova verzija aplikacije rade dok dodatna kolona postoji. Vraćanje deploya ne traži vraćanje baze.
  • Down skripta. Koristimo je kada je izmjena još samo na stagingu, ili kada je down korak pravi obrat (brisanje indeksa koji ste upravo napravili) i odrađen je na kopiji.
  • Point-in-time recovery. Prava sigurnosna mreža za loš backfill. PostgreSQL WAL ili MySQL binarni logovi vraćaju minut prije greške. Down skripta ne može popraviti redove koje je prepisala.

PostgreSQL može više DDL iskaza staviti u jednu transakciju, pa neuspjela migracija ne ostavlja napola primijenjenu izmjenu. MySQL oko mnogih DDL iskaza implicitno radi commit, zato te korake dijelimo i svaki pravimo tako da se može ponovo pokrenuti. U oba slučaja način pada zapisujemo prije releasea, a ne smišljamo ga tokom njega.

Integritet podataka prije i poslije izmjene

Migracija koja „uspije”, a tiho odbaci ili duplira redove, gora je od one koja padne. Provjere integriteta podataka dio su skripte, a ne naknadnog tiketa.

  • Ograničenja čuvaju podatke: strani ključevi, CHECK, jedinstveni indeksi i NOT NULL. Novo NOT NULL dodajemo tek kada je backfill popunio svaki postojeći red.
  • Backfill ide u serijama sa pauzom, da ne drži dugi lock i da jednom ogromnom transakcijom ne napuni disk.
  • Prije i poslije poredimo brojeve, null vrijednosti i checksume kolona koje smo dirali. Uzorak redova provjeravamo ručno kada je pravilo suptilno.
  • Upisi aplikacije tokom backfilla ulaze u računicu. Posao koji kopira stare redove i ignoriše nove ostavlja rupu. Dvostruki upis ili drugi prolaz za sustizanje tu rupu zatvara.
  • Staging koristi svježu, anonimizovanu kopiju produkcije kada je rizik u obliku podataka, a ne u SQL sintaksi.

Kod prodavnica neuspjela migracija narudžbi je izgubljen prihod. Mjerilo koje koristimo isto je kao u tekstu o e-commerceu bez gubitka podataka: svaka narudžba koja je postojala prije izmjene postoji i poslije nje, a nove narudžbe i dalje stižu.

Izmjene bez prekida rada: expand i contract

Expand i contract je način da živu šemu mijenjamo bez prozora za održavanje. Expand dodaje nešto što stari kod može ignorisati. Contract uklanja stari oblik tek kada je svaka pokrenuta instanca prešla dalje.

-- expand: old and new app versions both tolerate this ALTER TABLE orders ADD COLUMN currency char(3); -- backfill in batches, then a default for new rows ALTER TABLE orders ALTER COLUMN currency SET DEFAULT 'EUR'; -- contract, only after every instance writes currency ALTER TABLE orders ALTER COLUMN currency SET NOT NULL; ALTER TABLE orders ADD CONSTRAINT orders_currency_chk CHECK (currency IN ('EUR', 'USD', 'BAM')) NOT VALID; ALTER TABLE orders VALIDATE CONSTRAINT orders_currency_chk;

Podjela na NOT VALID i VALIDATE CONSTRAINT bitna je na PostgreSQL-u: prvi korak je brz, drugi provjerava postojeće redove a da ne blokira pisanje onako kako bi to uradio jedan ADD CONSTRAINT. Na novijim verzijama PostgreSQL-a dodavanje nullable kolone ili kolone sa konstantnim defaultom ne prepisuje tabelu. MySQL je manje popustljiv na velikim tabelama, pa za svaku izmjenu biramo online DDL ili alat koji kopira tabelu preko triggera i to kažemo prije nego što je zakažemo.

Preimenovanje ljudi često potcjenjuju. Ono odjednom lomi svaku staru instancu. Dodamo novu kolonu, pišemo u obje, uradimo backfill, prebacimo čitanje, pa staro ime obrišemo u kasnijem releaseu. Isti obrazac važi kada dijelimo ili spajamo tabele, uključujući pomjeranja iz vodiča za sharding i particioniranje.

Poređenje alata za migracije

Pravi alat je obično onaj koji vaš framework već pokreće, sve dok opasni koraci ostanu vidljivi na recenziji. Ne uvodimo drugi migrator pored postojećeg.

AlatTipičan stackStilPrednostNa šta paziti
Laravel migracijePHP / LaravelPHP klaseDolazi uz framework, timu je poznatSpore izmjene podataka skrivene u up()
FlywayBilo koji SQL, CLI ili JVMVerzionisani SQL fajloviJednostavan, pregledan, nezavisan od engineaBrojevi verzija koji se sudare između grana
LiquibaseBilo koji SQL, CLI ili JVMChangesetovi u SQL-u, YAML-u ili XML-uPreduslovi, konteksti, razlike po okruženjuFormat changelog-a koji tim mora naučiti
AlembicPython / SQLAlchemyPython revizijePrilagođen SQLAlchemy modelimaAutogenerate izlaz koji i dalje traži ljudski prolaz
Prisma MigrateNode.jsDeklarativna šemaBrz tok rada za Prisma aplikacijeShadow baza i drift u odnosu na staru produkciju
golang-migrateGo ili bilo šta, preko CLI-jaUpareni up/down SQLMali, eksplicitan, lak za CIProces i disciplinu držite vi

Flyway koncepti migracija i Liquibase model changelog-a reference su na koje upućujemo timove kada aplikacija nije Laravel. Za Laravel je zvanična dokumentacija migracija polazna tačka, a mi na nju dodajemo pravila za lockove i rad u serijama.

Najčešće greške u migracijama šeme

  • Izmjena migracije koju je produkcija već primijenila, pa sljedeće okruženje iz istog imena fajla izgradi drugačiju šemu.
  • UPDATE od više miliona redova u jednoj transakciji, koji naduva WAL ili binarni log i drži lockove kroz špicu.
  • CREATE INDEX bez CONCURRENTLY na zauzetoj PostgreSQL tabeli, što blokira pisanje dok se indeks gradi.
  • Ručni SQL na produkciji koji se nikada ne vrati u Git. Sljedeći restore ili novo okruženje to ne mogu ponoviti.
  • Povjerenje u neisprobanu down migraciju kao plan za incident.
  • Dva servisa migriraju istu bazu bez dogovorenog redoslijeda.

Šta košta automatizacija migracija baze podataka

Procjenu dajemo nakon što pogledamo repozitorijum, veličinu vrućih tabela i način na koji se produkcija danas mijenja. Faktori su:

  • Uvođenje alata i baseline postojeće baze, naspram proširenja Laravel ili Prisma postavke koju već imate.
  • Koliko je čekajućih izmjena destruktivno i da li moraju izaći bez prozora za prekid.
  • Veličina tabele. Nullable kolona na maloj tabeli je pitanje minuta. Backfill ili MySQL obnova velike tabele je planirana operacija.
  • Okruženja i CI: jedan pipeline je manje posla od niza servisa sa šemama koje su se razišle.
  • Želite li jednokratno sređivanje ili konvenciju koju i dalje primjenjujemo uz kasnije izmjene.

Kako radimo

  1. Analiza: poredimo Git, staging i produkciju, nabrajemo objekte koji postoje samo na serveru i bilježimo veličine tabela i lockove.
  2. Plan: biramo alat, baseline, koje izmjene idu kroz expand/contract i redoslijed deploya.
  3. Izrada: pišemo skripte, CI provjeru i batch poslove za backfill.
  4. Testiranje: cijeli lanac primjenjujemo na praznu bazu i na kopiju sličnu produkciji, uključujući neuspio korak i restore.
  5. Puštanje u rad: migracije i kod izlaze dogovorenim redom, uz nadzor lockova i grešaka tokom releasea.
  6. Podrška: konvenciju ostavljamo dokumentovanu i po želji pregledamo kasnije migracije prije nego što stignu na produkciju.

Zašto CodeWiz

  • Pišemo i aplikaciju: izmjene u Laravelu, Node.js-u i WordPressu planiramo zajedno sa šemom, a ne preko zida.
  • Open-source na prvom mjestu: Flyway, Liquibase, Laravel, Alembic i golang-migrate vas drže dalje od plaćenog proizvoda za šemu.
  • Bez predstave: ako izmjena traži kratak prozor za održavanje, kažemo to umjesto da obećamo nula prekida za prepisivanje tabele.
  • Fer cijene: vrhunski razvoj bez vrhunskih cijena, iz Banje Luke, uz rad na daljinu sa klijentima iz regiona i svijeta.
  • Podaci i isporuka zajedno: backupi, deployi i šema stoje u jednom planu. Više o CodeWizu.

Često postavljana pitanja

Koliko košta automatizacija migracija baze podataka?

Baseline jedne aplikacije i provođenje novih izmjena kroz CI mali je projekat. Zaostatak rizičnih produkcijskih izmjena, veliki backfillovi i više servisa veći su posao. Pisanu procjenu dobijate nakon što vidimo šemu i proces releasea.

Koliko traje uvođenje verzionisanih migracija?

Timu koji već koristi Laravel ili Prisma migracije uglavnom trebaju konvencija i CI provjera, što je nekoliko dana. Baza koja se godinama mijenjala samo ručno traži baseline i prvi siguran release, često jednu do dvije sedmice uključujući probu na kopiji.

Da li uzeti Flyway, Liquibase ili migrator frameworka?

Uzmite migrator koji framework već ima ako će tim fajlove zaista pregledati. Flyway birajte kada želite običan SQL kroz više jezika. Liquibase birajte kada trebaju preduslovi i različiti changesetovi po okruženju. Nećemo dodati drugi alat pored onog koji je već u upotrebi.

Mogu li izmjene šeme ići bez prekida rada?

Proširujuće izmjene obično mogu: nove kolone, novi indeksi građeni konkurentno, ograničenja provjerena u drugom koraku. Preimenovanja, promjene tipa i velike MySQL obnove tabela traže expand/contract ili kratak, dogovoren prozor. Svaku izmjenu svrstamo prije nego što je zakažemo.

Šta se dešava ako migracija padne na pola puta?

Na PostgreSQL-u se DDL unutar transakcije vraća zajedno. Na MySQL-u mnogi DDL iskazi sami sebi urade commit, zato svaki korak ostavljamo tako da se može ponovo pokrenuti i znamo koji je posljednji zabilježen. Loš backfill vraćamo point-in-time recoveryjem iz backupa uzetog prije releasea. Prije nego što se na taj backup oslonimo, provjerimo da se zaista vraća.

Možete li preuzeti bazu koja se godinama mijenjala ručno?

Možemo. Strukturu sa živog servera snimimo, tretiramo je kao baseline i od te tačke šemu mijenja samo Git. Razlike između produkcije i ostalih okruženja nabrajamo i ili ih usvajamo ili uklanjamo namjerno, a ne ostavljamo kao iznenađenje.

Stavite šemu pod kontrolu verzija

Recite nam kako danas mijenjate bazu i kojeg se releasea plašite. Predlažemo skripte, pipeline i rollback koji možete uvježbati. Kontaktirajte nas da počnemo, ili pogledajte naše usluge automatizacije migracija baze.