Journal-indexDockup / praktijknotitie
Note / database-backups-you-have-restored

Een backup die je nooit hebt teruggezet, is geen backup

Ongeteste database-backups mislukken op voorspelbare manieren: lege dumps, ontbrekende rollen, verkeerde flags of een ontbrekende encryptiesleutel. Leer hoe je een restore controleert, zodat het bestand dat je bewaart ook daadwerkelijk werkt.

Het slechtste moment om te ontdekken dat een backup niet werkt, is het moment waarop je hem nodig hebt. Toch is dat precies het meest voorkomende patroon: backups worden één keer ingesteld, er staat achttien maanden lang een groen vinkje in een dashboard en vervolgens levert een restore een lege database op.

Een database-backup testen door die terug te zetten is geen best practice die je, zoals de meeste best practices, desgewenst kunt overslaan. Een backup is een bewering en totdat je er een hebt teruggezet, is het een onbewezen bewering.

Dit is hoe backups mislukken en wat een echte controle moet verifiëren.

De vier manieren waarop een backup stilletjes nutteloos is

1. Hij is leeg en niemand heeft gekeken

Een pg_dump die halverwege mislukt, kan nog steeds een bestand opleveren. Een dump die tegen de verkeerde databasenaam wordt uitgevoerd, levert een geldig, correct en leeg bestand op. Voor alles wat alleen controleert op een exitcode die niet nul is of op het bestaan van een bestand, lijkt dit in beide gevallen een succes.

De goedkoopste controle ter wereld: bekijk de grootte en vergelijk die met die van gisteren. Een backup van 400 bytes terwijl die van gisteren 40 MB was, vertelt je alles wat je moet weten. Een backup die al zes maanden 400 bytes groot is, probeert je dat al die tijd te vertellen.

2. Hij bevat data, maar niet wat eromheen zit

pg_dump van één database bevat geen rollen en geen andere databases. Zet je hem terug op een nieuwe server, dan komen de tabellen aan terwijl elke GRANT verwijst naar een rol die niet bestaat. Je app maakt verbinding en krijgt overal permission denied.

Met extensions is het hetzelfde verhaal. Als je schema afhankelijk is van pgcrypto of uuid-ossp en het doel deze niet heeft, mislukt de restore halverwege en houd je een database met slechts enkele tabellen over.

3. De flags waren verkeerd voor de restore die je nodig hebt

pg_dump levert verschillende resultaten op, afhankelijk van het format. Meestal ontdek je de fout pas onder druk:

  • Plain SQL wordt teruggezet met psql en is leesbaar voor mensen. Je kunt het niet selectief terugzetten en het is traag voor grote databases.
  • Custom format (-Fc) wordt teruggezet met pg_restore, ondersteunt parallelism en selectief terugzetten en is wat je wilt voor alles van enige omvang.

Een backup maken in plain format omdat de tutorial dat deed, om vervolgens tijdens een incident te ontdekken dat je niet één tabel kunt terugzetten: dat is een heel specifiek en vermijdbaar soort slechte dag.

4. Je kunt hem niet decrypten

Als backups encrypted zijn — en dat zouden ze moeten zijn — maakt de sleutel deel uit van de backup. Een sleutel die alleen op de verloren machine staat, of alleen in een environment variable van de service die uitgevallen is, is een sleutel waar je niet over beschikt wanneer het erop aankomt.

Hoe een echte controle eruitziet

De test is niet "bestaat het bestand?" Het is zet het ergens anders terug en stel de database een vraag.

# 1. Restore into a scratch database, not the live one
createdb verify_$(date +%Y%m%d)
pg_restore -d verify_$(date +%Y%m%d) --no-owner --no-privileges latest.dump

# 2. Ask it something only real data can answer
psql -d verify_$(date +%Y%m%d) -c "
  select
    (select count(*) from users)            as users,
    (select count(*) from orders)           as orders,
    (select max(created_at) from orders)    as newest_order;
"

# 3. Drop it
dropdb verify_$(date +%Y%m%d)

Stap 2 is het hele punt. Een restore die zonder fouten wordt voltooid, vertelt je nog steeds niets over de vraag of de data er daadwerkelijk staat. Row counts en een controle van de recentste data doen dat wel.

Drie dingen die je moet controleren:

  • De row counts liggen in de juiste orde van grootte. Niet exact — data verandert — maar een tabel met eerst 200.000 rijen en nu 12 rijen is een mislukking.
  • Het nieuwste record is recent. Als de recentste order in je "nightly" backup uit maart komt, is je backupjob in maart gestopt.
  • De app kan daadwerkelijk verbinding maken. Laat een staginginstance verbinding maken met de teruggezette database en laad één pagina.

Doe het volgens een schema, niet pas als er een incident is

Een realistische frequentie is maandelijks en geautomatiseerd, met het resultaat op een plek waar je het opmerkt. Een agendaherinnering met "backups testen" is een herinnering die je op snooze zet.

Wat ervoor zorgt dat dit blijft werken, is de fout luid en duidelijk maken: als de verification query minder rijen oplevert dan een bepaalde drempelwaarde, moet dat op dezelfde manier iemand alarmeren als een production error. Een backupsysteem dat stilletjes faalt, is niet te onderscheiden van helemaal geen backupsysteem — totdat het erop aankomt.

Hoe Dockup dit aanpakt

Drie beslissingen, elk gericht op een specifieke fout hierboven.

Backups gaan ergens anders heen. Een backup op dezelfde schijf als de database is geen backup — het is een kopie die samen met de schijf verloren gaat. Dockup streamt database-backups rechtstreeks naar object storage terwijl ze worden gemaakt, zodat het bestand nooit afhankelijk is van de host waarop het is aangemaakt.

Ze zijn encrypted en de sleutel staat niet op de machine. Backups worden tijdens het streamen encrypted met AES-256-GCM. Voor recovery is vooral belangrijk dat de sleutel door het platform wordt beheerd en niet in de environment van de service staat waarvan een backup wordt gemaakt.

Een backup die niets heeft opgeleverd, wordt niet als backup geregistreerd. Dit pakt het probleem met lege bestanden rechtstreeks aan: als de dump eindigt met een exitcode die niet nul is of nul bytes oplevert, wordt de upload verwijderd en wordt de backup als mislukt geregistreerd. Je houdt dus geen lijst met groene vermeldingen over waarvan er één een bestand van 400 bytes is.

dockup db backup my-project/main-db --json     # take one now
dockup db backups my-project/main-db --json    # list them with sizes

De groottes in deze lijst zijn de goedkoopste health check die je hebt. Houd de trend in de gaten.

De ongemakkelijke vraag

Als je production database de komende tien minuten wordt vernietigd, hoe lang duurt het dan voordat je hem terug hebt en hoeveel data ben je kwijt?

Als je beide getallen niet kunt noemen, heb je geen backupstrategie — je hebt backupbestanden. Het verschil zit volledig in de vraag of iemand ooit de restore heeft uitgevoerd.

Veelgestelde vragen

Hoe vaak moet ik een restore testen? Maandelijks is een redelijke standaard, en geautomatiseerd in plaats van handmatig. Het belangrijkste is dat een fout luid en duidelijk wordt gemeld, niet dat de frequentie zo hoog mogelijk is.

Waarom werd mijn restore voltooid zonder dat er data was? Meestal is de dump tegen de verkeerde database gemaakt of is hij halverwege mislukt terwijl er nog naar een bestand werd geschreven. Vergelijk de groottes van backups in de loop van de tijd — een lege dump valt op in een trend van bestandsgroottes, maar is onzichtbaar in een statuskolom.

Moeten backups encrypted zijn? Ja, en de sleutel moet ergens staan waar hij het verlies van de machine overleeft. Een encrypted backup waarvan de sleutel op de verloren server stond, kan niet worden hersteld.

Is een snapshot hetzelfde als een backup? Nee. Een volume-snapshot legt de schijf vast, inclusief de toestand waarin de database zich op dat moment bevond. Een logical dump is per definitie consistent. De meeste teams willen beide, voor verschillende soorten incidenten.