Výchozí stav
Produkční databáze registru FRED běží, stejně jako všechny ostatní systémy registru, výhradně na fyzických serverech, a to ve třech, geograficky oddělených lokalitách. Jedná se o databázový cluster v režimu 1× master a 2× slave (v režimu read-only), ve kterém pro synchronizaci dat používáme tzv. streaming replikaci. Ta funguje na principu, že je mezi master a jednotlivými slave servery otevřeno síťové spojení, po kterém se předávají tzv. WAL logy (Write-Ahead Log) okamžitě poté, co jsou na master instanci zpracovány.
Na všech třech databázových serverech jsme provozovali Ubuntu 18.04 LTS a PostgreSQL verze 9.6, pro kterou měla ke konci roku 2021 skončit oficiální podpora. Samotná velikost databáze (oproti např. databázi logů v jednotkách terabajtů) nebyla nikterak veliká. Jednalo se o přibližně 100 GB.
Úvahy a plán upgrade
V rámci upgradu jsme uvažovali, kromě povýšení verze PostgreSQL, také o aktualizaci operačního systému, ačkoliv oficiální podpora Ubuntu 18.04 LTS skončí až v dubnu roku 2023. Balíky PostgreSQL používáme výhradně z oficiálního repozitáře apt.postgresql.com, takže kdybychom zůstali na původní verzi Ubuntu, nejednalo by se o žádnou zásadní provozní komplikaci. Ovšem vzhledem k tomu, že jsme chtěli přejít na co nejnovější verzi PostgreSQL s co nejdelší podporou, mělo smysl mít z pohledu podpory „sladěný“ i operační systém. Volba nakonec padla na Debian Linux 11, který oficiálně vyšel v srpnu roku 2021 a PostgreSQL verze 13.
Samotný upgrade jsme rozdělili na dvě části. Ta první spočívala v testování v interním testovacím prostředí a to nad anonymizovanými daty. Zde jsme se zaměřili čistě na kompletní funkčnost jednotlivých komponent registru. Testování probíhalo nad standardními testovacími scénáři stejně, jako bychom testovali např. standardní aplikační vydání před nasazením do produkce.
Hlavním cílem tohoto testování bylo zjistit, zda se aplikace chová na nové verzi databáze stejně, případně zjistit jaké změny v kódu je potřeba v aplikacích udělat. V této fázi jsme neřešili výkonnost databáze, metody samotného upgrade a další kroky na straně administrátorů. Zkrátka jsme co nejjednodušeji připravili nový virtuální server a naimportovali databázi z tzv. full-dumpu.
Ve druhé části jsme pracovali již v zcela odděleném a chráněném admin testovacím prostředí s produkčními daty v databázi a na co nejvíce podobné HW konfiguraci serveru, abychom mohli pro jednotlivé kroky zjistit přesnou dobu trvání a mohli tak vhodně naplánovat odstávku.
Testování v admin testovacím prostředí
Upgrade na vyšší verzi PostgreSQL jsme mohli provést dvěma způsoby. Buď pomocí pg_upgrade nebo provedením full-dumpu celé databáze a následného restore.
Metoda PG_UPGRADE
Jako první jsme vyzkoušeli upgrade pomocí pg_upgrade. Tato metoda spočívá v tom, že se provede upgrade PostgreSQL clusteru právě bez nutnosti full-dump a restore kroků. To se nám velice líbilo vzhledem k minimální nedostupnosti databáze. Uvažovali jsme totiž, že na novém serveru s Debian 11 nainstalujeme také PostgreSQL ve verzi 9.6, nastavíme streaming replikaci proti master serveru a poté při odstávce jen provedeme pg_upgrade nad aktuálními daty.
Jak jsme postupovali? Na databázový server jsme tedy nainstalovali obě verze PostgreSQL serveru, připravili funkční původní databázový cluster s zreplikovanou databází a inicializovali (prázdný) nový cluster ve verzi 13, který jsme zastavili. Následně jsme provedli již avizovaný upgrade. Jelikož se zde pracuje pouze na úrovni hard linků na souborovém systému, bylo vše hotovo během několika jednotek, maximálně desítek sekund. Nový databázový cluster jsme spustili a poté na základě doporučení upgrade scriptu provedli aktualizaci extensions a
postgres@db> vacuumdb –all -–analyze-in-stages
Na závěr bylo možné rovnou smazat původní databázový cluster. Tolik teorie a provedení v ideálních podmínkách. My jsme však narazili na problém už před spuštěním skriptu pg_upgrade. Tím problémem byly PostgreSQL data checksums, které se používají k detekcím chyb v datech při ukládání na disk. Myslím, že pro každého databázového administrátora je noční můra najít v logu např. chybu
ERROR: invalid page in block 0 of relation base/13455/16395
Checksumy jsou skvělou funkcionalitou, my jsme je ovšem zapnuté neměli. Utilita initdb, která se používá k inicializaci nového databázového clusteru je již standardně povoluje. A na tomto zjištění právě skončil upgradovací skript. Naštěstí bylo řešení jednoduché, v novém databázovém clusteru stačilo checksumy dodatečně vypnout
postgres@db> pg_checksums --disable /var/lib/postgresql/13/main/
Následně již upgrade proběhl úspěšně za neuvěřitelných sedm sekund.
Celý příkaz vypadal následovně:
postgres@db> /usr/lib/postgresql/13/bin/pg_upgrade --old-bindir=/usr/lib/postgresql/9.6/bin/ --new-bindir=/usr/lib/postgresql/13/bin/ --old-datadir=/var/lib/postgresql/9.6/main --new-datadir=/var/lib/postgresql/13/main/ --old-options='-c config_file=/etc/postgresql/9.6/main/postgresql.conf' --new-options='-c config_file=/etc/postgresql/13/main/postgresql.conf' --link
Provedení –analyze-in-stages na naší databázi trvalo přibližně 22 sekund. Celkově bychom se tedy dostali na necelou půl minutu čistého času, tedy velice krátká odstávka. Skvělé, že? Bohužel to nebyly všechny kroky. Checksumy jsme tedy potřebovali zapnout, což trvalo (při vypnuté databázi) přibližně 12 minut.
postgres@db> pg_checksums --progress --enable /var/lib/postgresql/13/main/
Nakonec zbývalo spustit ještě i reindexaci:
postgres@db> reindexdb -j 24 fred
Protože z dřívějších zkušeností víme, že pokud se přechází z jiného operačního systému (lhostejno, zda-li se jedná jen o povýšení stávající verze), je nutné kvůli systémových knihovnám libc, databázovým collations apod. provést rebuild všech indexů. V opačném případě se může stát, že v některých případech dotazy využívající indexy nevrací korektní výstupy. Celá reindexace ve čtyřiadvaceti vláknech trvala přibližně 10 minut. V tu chvíli by byla databáze připravená k provozu. Jenže jsme ještě neprovedli full-vacuum, který bylo také vhodné spustit. To nám vycházelo přibližně na 30 minut času.
Když jsem sečetl celkový čas na provedení povýšení verze PostgreSQL metodou pg_upgrade, dostali jsme se na necelou jednu hodinu čistého času. Když jsem k tomu připočetl i provedení full-backupu databáze před samotným spuštěním upgrade, která trvá přibližně 15 minut, celkový čas byl přibližně hodinu a čtvrt.
Metoda full-dump + restore
Pojďme si ještě v rychlosti projít, jak by upgrade, tedy z časového hlediska, vypadal druhou metodou. Kroky pro provedení jsou vlastně jednoduché. Nejdříve je potřeba zastavit běžící master instanci databáze, provést full-dump utilitou pg_dumpall (doba trvání přibližně 15 minut), přenést na nový server, naimportovat data (přibližně 20 minut) a na závěr provést analyze (přibližně 10 sekund). Reindexace a full-vacuum se v tomto případě nemusí provádět. Celkový čas? Do 40 minut.
Kterou cestou se vydáme, bylo tedy jasné, metoda full-dump + restore je kratší a méně náchylná na chyby, protože obsahuje méně kroků. Současně se datové soubory databáze zmenšily přibližně o 40 procent.
Upgrade produkčního prostředí
Konečně se dostávám k tomu, jak jsme postupovali v produkčním prostředí. Vycházeli jsme tedy z testování celého postupu v admin testovacím prostředí, kde jsme došli k názoru, že budeme upgradovat metodou full-dump + restore. U tak malé databáze si to můžeme z časového hlediska dovolit. V admin testovacím prostředí jsme však pouze trénovali, jak upgrade provést, nastavit replikaci a ověřit, že jsou data konzistentní. Jak to celé realizovat v produkčním prostředí, abychom co nejméně ovlivnili provoz a současně měli vždy „zadní vrátka“ bylo komplikovanější.
Připravili jsme schema změn a stavů serverů v jednotlivých krocích tak, jak bychom měli postupovat. Inspirovali jsme se upgradem databází před několika lety, kdy jsme také prováděli aktualizaci operačního systému a přecházeli na verzi PostgreSQL 9.6.
Postup se možná zdá být na první pohled trochu složitý, ale to je z důvodu, abychom zajistili co nejmenší překryv mezi jednotlivými upgrady serverů a současně měli vždy funkční jednu databázovou repliku.
Výchozí stav byl tedy zřejmý, všechny tři servery byly na stejné verzi systému a PostgreSQL. V prvním kroku jsme připravili na serveru č. 3 nový operační systém s oběma verzemi PostgreSQL. Pro verzi 9.6 navázali zpět replikaci s master instancí a verzi 13 zatím ponechali zastavenou.
V druhém kroku (jeden den před naplánovanou noční odstávkou) jsme na serveru č. 2 (budoucí master instance) provedli stejné kroky, jako v předchozím případě. S tím rozdílem, že databázový cluster 13 byl nastartovaný již v režimu master.
Na začátku nahlášené odstávky (krok č. 3) jsme provedli několik počátečních kroků. Tedy ve zkratce: zastavení provozu ke službě EPP, nastavení maintenance modů pro webové služby a mojeiD, zastavení generování .CZ zóny, všech cronů a služeb registru, nastavení firewallů a shození VIP IP adres databázových serverů. Následně již bylo možné provét full-dump databáze a následný restore na serveru č. 2. Tím se stal tento server master instancí pro verzi 13 a nadále však byl připraven server č. 1 jako master instance pro verzi 9.6 s jednou replikou pro případ návratu zpět (tzv. rollback).
Následovala sada interních testů, abychom si ověřili, že upgrade proběhl na výbornou. Jelikož bylo vše bez problémů, postupně jsme zapnuli všechny služby registru, odstranili jednotlivé maintenance módy, crony, firewally a nastavení VIP IP adresy. Poté jsme spustili generování .CZ zóny, ovšem nejdříve bez toho, aby se změny poslaly pomocí protokolu AXFR/IXFR na celý náš DNS anycast. Chtěli jsme si totiž nejdříve ověřit, že generování a všechny kontroly s tím spojené proběhnou v pořádku a my tak nerozbijeme český internet. Česká zóna byla v pořádku, povolili jsme transfer do DNS anycastu a na závěr nastavili databázovou replikaci i na server č. 3 (krok č.4).
Tím jsme dokončili naplánované práce v rámci noční odstávky, kterou jsme předem ohlásili (s rezervou) na čtyři hodiny. Reálně však odstávka databáze trvala přibližně dvě hodiny, neboť jsme ještě kromě full-dump + restore kroků provedli výše uvedené přípravné práce, kontroly, testy apod.
Po dvou dnech sledování provozu jsme provedli, již během dne, krok č. 5. Tedy upgrade posledního (původní master instance) serveru č. 1.
Vše se povedlo
Vše se povedlo díky spolupráci ostatních kolegů, v odhadovaném časovém okně odstávky a nemuseli jsme řešit návrat zpět.
Společně s upgradem jsme se také zaměřili na výkonnostní parametry databáze, u kterých jsme se inspirovali z webového konfigurátoru provozu PostgreSQL databází od společnosti Cybertec. Mimochodem, stejný subjekt stojí i za skvělým monitoringem databází pgwatch2, který jsme v letošním roce také nasadili do provozu.
Tímto úkolem jsme si myslím pěkně procvičili a oživili problematiku upgradů databází a na základě nabitých zkušeností můžeme přistoupit k upgrade databáze logů. Ale o tom zase někdy příště…
(Původně napsáno pro blog sdružení CZ.NIC.)