Kas yra PostgreSQL replikacija ir kodėl ji svarbi
Kai kuriate rimtą aplikaciją ar sistemą, kuri dirba su duomenimis, anksčiau ar vėliau susidursite su klausimu: o kas bus, jei serveris sugenda? Kaip užtikrinti, kad jūsų duomenys būtų prieinami net ir kritiniais momentais? Čia ir ateina į pagalbą PostgreSQL replikacija – mechanizmas, leidžiantis turėti kelis duomenų bazės egzempliorius, kurie sinchronizuojasi tarpusavyje.
PostgreSQL replikacija – tai procesas, kai viena duomenų bazė (master arba primary) automatiškai kopijuoja savo duomenis į vieną ar kelias kitas duomenų bazes (replica arba standby). Skamba paprasta, bet praktikoje tai gali išgelbėti jūsų verslą nuo rimtų problemų. Įsivaizduokite e-prekybos svetainę, kuri per Juodąjį penktadienį netikėtai praranda prieigą prie duomenų bazės – tai būtų katastrofa ne tik reputacijai, bet ir finansams.
Replikacija sprendžia ne tik prieinamumo klausimą. Ji leidžia paskirstyti apkrovą – skaitymo užklausas galite nukreipti į replicas, o rašymo operacijas palikti primary serveriui. Tai ypač aktualu sistemoms, kuriose skaitymo operacijų yra daug daugiau nei rašymo (o tokių sistemų yra absoliuti dauguma).
Pagrindiniai replikacijos tipai PostgreSQL
PostgreSQL palaiko kelis replikacijos tipus, ir kiekvienas turi savo nišą bei panaudojimo atvejus. Supratimas, kuris tipas tinka jūsų situacijai, yra kritiškai svarbus.
Streaming replikacija yra populiariausias ir greičiausias būdas. Ji veikia taip: primary serveris siunčia WAL (Write-Ahead Log) įrašus į standby serverius beveik realiu laiku. Tai reiškia, kad jūsų replicos yra labai artimos primary būsenai – dažniausiai atsilikimas siekia tik kelias milisekundes ar sekundes. Streaming replikacija gali būti sinchroninė arba asinchroninė. Sinchroninėje versijoje primary serveris laukia patvirtinimo iš bent vienos replicos prieš patvirtindamas transakciją – tai užtikrina maksimalų duomenų saugumą, bet šiek tiek sulėtina veikimą.
Loginė replikacija veikia kitaip – ji replikuoja ne WAL įrašus, o konkrečius duomenų pakeitimus loginiu lygmeniu. Tai leidžia replikuoti tik tam tikras lenteles ar net tik tam tikrus duomenų poaibius. Loginė replikacija yra lankstesnė, bet ir lėtesnė. Ji puikiai tinka situacijoms, kai reikia replikuoti tik dalį duomenų arba kai primary ir replica serveriai turi skirtingas PostgreSQL versijas.
Cascade replikacija leidžia sukurti hierarchinę replikacijos struktūrą. Viena replica gali būti šaltinis kitai replikai, taip sumažinant apkrovą primary serveriui. Tai ypač naudinga, kai turite daug replicas arba kai jos yra geografiškai paskirstytos.
Kaip sukonfigūruoti streaming replikaciją
Dabar pereikime prie praktikos. Sukonfigūruosime paprasčiausią streaming replikacijos scenarijų su vienu primary ir vienu standby serveriu. Tai nėra sudėtinga, bet reikia atlikti kelis svarbius žingsnius tiksliai.
Pirmiausiai primary serveryje reikia sukonfigūruoti postgresql.conf failą. Pagrindiniai parametrai:
wal_level = replica
max_wal_senders = 3
wal_keep_size = 1GB
hot_standby = on
Parametras wal_level nurodo, kiek informacijos bus rašoma į WAL – replica reikšmė yra būtina replikacijai. max_wal_senders nurodo maksimalų vienu metu veikiančių WAL siuntėjų skaičių – paprastai nustatykite šią reikšmę šiek tiek didesnę nei planuojamų replicas skaičius. wal_keep_size nurodo, kiek WAL failų laikyti serveryje – tai apsaugo nuo situacijos, kai replica trumpam atsijungia ir grįžusi nebegali gauti reikalingų WAL įrašų.
Toliau reikia sukonfigūruoti autentifikaciją. Faile pg_hba.conf pridėkite eilutę, leidžiančią replica serveriui prisijungti:
host replication replicator 192.168.1.0/24 md5
Čia replicator yra vartotojo vardas, kurį sukursite replikacijai (galite pasirinkti bet kokį kitą pavadinimą), o 192.168.1.0/24 yra IP adresas ar tinklas, iš kurio leidžiama jungtis.
Primary serveryje sukurkite replikacijos vartotoją:
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'stiprus_slaptazodis';
Dabar pereikime prie standby serverio. Paprasčiausias būdas sukurti pradinę kopiją – naudoti pg_basebackup įrankį:
pg_basebackup -h primary_serverio_ip -D /var/lib/postgresql/14/main -U replicator -P -v -R -X stream
Šis komandas nukopijuos visą duomenų bazę iš primary serverio ir automatiškai sukurs reikalingus konfigūracijos failus. Parametras -R yra ypač naudingas – jis sukuria standby.signal failą ir prideda reikalingus nustatymus į postgresql.auto.conf.
Monitoringas ir problemų sprendimas
Sukonfigūravus replikaciją, darbas nesibaigė – dabar reikia ją prižiūrėti. PostgreSQL suteikia keletą būdų stebėti replikacijos būseną.
Primary serveryje galite patikrinti prijungtas replicas naudodami:
SELECT * FROM pg_stat_replication;
Ši užklausa parodys visas aktyvias replicas, jų būseną, atsilikimą baitais ir kitą naudingą informaciją. Ypač svarbus stulpelis yra state – jis turėtų rodyti streaming, jei viskas veikia gerai.
Standby serveryje galite patikrinti atsilikimą nuo primary:
SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) AS lag_seconds;
Tai parodys, kiek sekundžių replica atsilieka nuo primary. Jei ši reikšmė pradeda augti, tai signalas, kad kažkas negerai – galbūt tinklo problemos, galbūt replica serveris nebesusp spręsti apkrovos.
Dažniausios problemos, su kuriomis susidursite:
Replica atsilieka per daug. Tai gali nutikti, jei primary serveryje vyksta labai intensyvūs pakeitimai, o replica serveris neturi pakankamai resursų juos apdoroti. Sprendimas – padidinti replica serverio resursus arba optimizuoti užklausas primary serveryje.
Replikacija nutrūksta po serverio perkrovimo. Dažniausiai tai nutinka, kai primary serveris jau ištrynė WAL failus, kurių reikia replikai. Sprendimas – padidinti wal_keep_size arba naudoti replikacijos slotus (replication slots), kurie užtikrina, kad reikalingi WAL failai nebus ištrinti.
Sinchroninė replikacija sulėtina sistemą. Jei naudojate sinchroninę replikaciją, bet ji per daug sulėtina operacijas, galite perjungti į asinchroninę arba naudoti synchronous_commit = remote_write vietoj on – tai šiek tiek sumažina garantijas, bet pagerina našumą.
Failover ir switchover scenarijai
Vienas iš svarbiausių replikacijos aspektų – gebėjimas greitai perjungti į replica serverį, kai primary serveris tampa neprieinamas. Yra du pagrindiniai scenarijai: failover (neplanuotas perjungimas) ir switchover (planuotas perjungimas).
Failover vyksta, kai primary serveris netikėtai sugenda. Tokiu atveju reikia paaukštinti (promote) vieną iš standby serverių į naują primary. PostgreSQL tai padaryti paprasta:
pg_ctl promote -D /var/lib/postgresql/14/main
Arba tiesiog sukurkite failą promote duomenų kataloge. Standby serveris automatiškai sustabdys replikaciją ir taps pilnateisiu primary serveriu, priimančiu rašymo operacijas.
Tačiau čia slypi keletas spąstų. Pirma, jei turėjote kelias replicas, jas reikės perkonfigūruoti, kad jos dabar replikuotųsi iš naujo primary. Antra, kai senasis primary serveris vėl atsistatys, jis negalės tiesiog grįžti kaip replica – gali būti duomenų neatitikimų. Tokiu atveju dažniausiai reikia jį perkurti naudojant pg_rewind įrankį arba visiškai perkurti naudojant pg_basebackup.
Switchover yra planuotas perjungimas, pavyzdžiui, techninės priežiūros metu. Procesas panašus, bet čia galite jį atlikti kontroliuojamiau:
1. Sustabdykite naujų transakcijų priėmimą primary serveryje
2. Palaukite, kol visos replicos pasivys primary
3. Paaukštinkite pasirinktą standby į primary
4. Perkonfigūruokite senąjį primary kaip standby
Šis procesas užtikrina, kad neprarasite jokių duomenų ir perjungimas vyks sklandžiai.
Automatizuotas failover su Patroni
Rankinis failover yra gerai kontroliuojamas, bet kas nutinka, kai primary serveris sugenda 3 val. nakties, o jūs miegote? Čia į pagalbą ateina automatizuoti sprendimai, tokie kaip Patroni.
Patroni yra atviro kodo įrankis, kuris automatiškai valdo PostgreSQL replikaciją ir atlieka failover, kai reikia. Jis naudoja paskirstytą konfigūracijos saugyklą (etcd, Consul arba ZooKeeper), kad koordinuotų kelių serverių darbą ir priimtų sprendimus apie tai, kuris serveris turėtų būti primary.
Patroni veikimo principas paprastas: kiekviename serveryje veikia Patroni agentas, kuris nuolat stebi serverio būseną ir bendrauja su kitais agentais per paskirstytą konfigūracijos saugyklą. Jei primary serveris tampa neprieinamas, Patroni automatiškai išrenka naują primary iš turimų standby serverių ir perkonfigūruoja kitus serverius.
Patroni konfigūracija gali atrodyti bauginančiai, bet iš tikrųų ji gana logiška. Štai supaprastintas pavyzdys:
scope: postgres-cluster
name: node1
restapi:
listen: 0.0.0.0:8008
connect_address: node1:8008
etcd:
host: etcd-server:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
listen: 0.0.0.0:5432
connect_address: node1:5432
data_dir: /var/lib/postgresql/14/main
authentication:
replication:
username: replicator
password: stiprus_slaptazodis
Patroni taip pat suteikia REST API, per kurį galite stebėti klasterio būseną ir atlikti įvairias operacijas. Tai labai patogu integruojant su monitoringo sistemomis ar load balanceriais.
Apkrovos paskirstymas ir skaitymo replicos
Vienas iš pagrindinių replikacijos privalumų – galimybė paskirstyti apkrovą. Dauguma aplikacijų atlieka daug daugiau skaitymo nei rašymo operacijų, todėl galite nukreipti skaitymo užklausas į standby serverius, o rašymo – palikti primary serveriui.
Tačiau čia reikia suprasti vieną svarbų dalyką: standby serveriai gali šiek tiek atsilikti nuo primary. Jei jūsų aplikacija įrašo duomenis ir iš karto bando juos perskaityti iš replicos, gali būti, kad duomenys dar nebus pasiekiami. Tai vadinama replication lag problema.
Yra keletas būdų su tuo susidoroti:
Session-based routing. Kai vartotojas atlieka rašymo operaciją, jo sesija tam tikrą laiką (pvz., 5 sekundes) nukreipiama tik į primary serverį. Po to vėl gali naudoti replicas.
Lag-aware routing. Prieš nukreipiant užklausą į replica, patikrinkite jos atsilikimą. Jei atsilikimas per didelis, nukreipkite į primary arba į kitą replica, kuri mažiau atsilieka.
Aplikacijos lygio kontrolė. Kritines užklausas, kurioms reikia naujausių duomenų, visada siųskite į primary. Mažiau kritines – į replicas.
Praktiškai tai įgyvendinti galite naudodami connection pooler’ius kaip PgBouncer arba specializuotus load balancer’ius kaip HAProxy ar PgPool-II. Pavyzdžiui, HAProxy konfigūracijoje galite nustatyti, kad jis tikrintų kiekvieno serverio būseną ir nukreiptų užklausas tik į sveikus serverius:
listen postgres_read
bind *:5433
option pgsql-check user health_check
balance roundrobin
server replica1 192.168.1.11:5432 check
server replica2 192.168.1.12:5432 check
server replica3 192.168.1.13:5432 check
Kai replikacijos nebepakanka: multi-master sprendimai
Standartinė PostgreSQL replikacija yra vieno master tipo – tik vienas serveris priima rašymo operacijas. Bet kartais reikia daugiau – pavyzdžiui, kai turite geografiškai paskirstytą sistemą ir norite, kad kiekviename regione būtų galima rašyti duomenis lokaliai.
Čia ateina į pagalbą multi-master replikacijos sprendimai. PostgreSQL pats to nepalaiko natyviai, bet yra keletas išplėtimų:
BDR (Bi-Directional Replication) – komercinis sprendimas nuo 2ndQuadrant (dabar EDB), leidžiantis turėti kelis aktyvius master serverius. Jis sprendžia konfliktų problemą (kai tas pats įrašas keičiamas dviejuose serveriuose vienu metu) naudodamas įvairias strategijas.
Citus – horizontalaus skaljavimo sprendimas, kuris paskirsto duomenis per kelis serverius. Nors tai ne visiškai multi-master, jis leidžia skaliavimuisi, kurio neįmanoma pasiekti su paprasta replikacija.
Bucardo – atviro kodo asinchroninė multi-master replikacija. Ji lankstesnė nei streaming replikacija, bet ir sudėtingesnė konfigūruoti.
Tačiau būkite atsargūs su multi-master sprendimais. Jie įneša papildomą sudėtingumą ir gali sukelti sunkiai diagnozuojamų problemų. Dažniausiai geriau pradėti nuo paprastos master-standby replikacijos ir pereiti prie sudėtingesnių sprendimų tik tada, kai tikrai reikia.
Ką reikia žinoti prieš paleidžiant į produkciją
Replikacija nėra „nustatyk ir pamiršk” sprendimas. Prieš paleisdami ją produkcinėje aplinkoje, įsitikinkite, kad esate pasirengę:
Testuokite failover scenarijus. Ne teorijoje, o praktikoje. Sustabdykite primary serverį ir įsitikinkite, kad galite greitai ir patikimai pakelti standby. Išmatuokite, kiek laiko tai užtrunka. Įsitikinkite, kad jūsų aplikacija teisingai persijungia prie naujo primary.
Automatizuokite monitoringą. Nustatykite alertus, kurie praneš, jei replikacija atsilieka, jei serveris tampa neprieinamas, jei diske baigiasi vieta. Naudokite įrankius kaip Prometheus su postgres_exporter, Zabbix, Nagios ar bet kokį kitą monitoringo sprendimą, kurį jau naudojate.
Planuokite backup strategiją. Replikacija nėra backup! Jei kažkas ištrina svarbią lentelę primary serveryje, ta pati operacija bus perduota į replicas. Jums vis tiek reikia reguliarių backup’ų. Naudokite įrankius kaip pg_dump, pg_basebackup arba specializuotus sprendimus kaip pgBackRest ar Barman.
Dokumentuokite procedūras. Kai 3 val. nakties kažkas sugenda, jūs nenorite ieškoti, kaip atlikti failover. Turėkite aiškias, išbandytas procedūras, kurias gali vykdyti bet kuris komandos narys.
Apsvarstykite tinklo konfigūraciją. Replikacija perduoda daug duomenų, ypač jei turite intensyvų rašymą. Įsitikinkite, kad jūsų tinklas išlaiko apkrovą. Jei replicas yra skirtinguose duomenų centruose, apsvarstykite tinklo latency poveikį.
Replikacija – tai galingas įrankis, bet kaip ir bet kuris galingas įrankis, ji reikalauja supratimo ir atsakingo naudojimo. Pradėkite paprastai – vienas primary, viena ar dvi standby replicas. Išmokite, kaip tai veikia, kaip stebėti, kaip reaguoti į problemas. Tik tada, kai tikrai reikia, pereikite prie sudėtingesnių konfigūracijų su automatizuotu failover, geografiškai paskirstytomis replikomis ar multi-master sprendimais. Duomenų prieinamumas yra kritiškai svarbus, bet pernelyg sudėtinga sistema gali tapti prieinamumo priešu, o ne draugu.
