Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Në këtë artikull do të flas për mënyrën se si i qasëm çështjes së besueshmërisë së PostgreSQL, pse ishte e rëndësishme për ne dhe çfarë arritëm në fund.

Ne kemi një shërbim me ngarkesë të lartë: 2.5 milion përdorues në të gjithë botën, mbi 50,000 përdorues aktivë çdo ditë. Serverët ndodhen në Amazon në një rajon të Irlandës: në punë janë vazhdimisht mbi 100 serverë të ndryshëm, nga të cilët pothuajse 50 janë me bazat e të dhënave.

Backend-i ynë është një aplikacion i madh monolit dhe stateful në Java, i cili mban një lidhje websocket të vazhdueshme me klientin. Kur disa përdorues punojnë në të njëjtën pult, të gjithë ata shohin ndryshimet në kohë reale, sepse çdo ndryshim e regjistrojmë në bazën e të dhënave. Ne kemi rreth 10,000 kërkesa në sekondë në bazat tona. Në ngarkesën maksimale në Redis shkruajmë nga 80-100,000 kërkesa në sekondë.
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Pse kaluam nga Redis në PostgreSQL

Fillimisht, shërbimi ynë punonte me Redis, një magazinë key-value që mban të gjitha të dhënat në memorie server.

Avantazhet e Redis:

  1. Shpejtësi e lartë përgjigjeje, sepse gjithçka ruhet në memorie;
  2. Lehtësia e backup-it dhe replikimit.

Disavantazhet e Redis për ne:

  1. Nuk ka transaksione reale. Ne përpiqeshim t'i imitojmë ato në nivelin e aplikacionit tonë. Fatkeqësisht, kjo nuk ka funksionuar gjithmonë mirë dhe kërkonte shkruajtjen e kodit shumë të komplikuar.
  2. Vëllimi i të dhënave është i kufizuar nga sasia e memorjes. Ndërsa rritet sasia e të dhënave, memoria do të rritet gjithashtu, dhe, në fund, do të hasim në karakteristikat e instancës së zgjedhur, gjë që në AWS kërkon ndalimin e shërbimit tonë për të ndryshuar tipin e instancës.
  3. Është e nevojshme që të ruhet vazhdimisht një nivel i ulët latency, sepse kemi një numër shumë të madh kërkesash. Niveli optimal i vonesës për ne është 17-20 ms. Me një nivel 30-40 ms, ne marrim përgjigje të gjata në kërkesat e aplikacionit tonë dhe degradimin e shërbimit. Fatkeqësisht, kjo na ndodhi në shtator 2018, kur një nga instancat me Redis për një arsye mori një latency dyfish më të lartë se zakonisht. Për të zgjidhur problemin, ndaluam shërbimin në mes të ditës për një mirëmbajtje të paplanifikuar dhe zëvendësuam instancën problematike të Redis.
  4. Është e lehtë të marrësh konsistencë të dhënash të papërputhshme edhe nga gabime të vogla në kod dhe pastaj të harxhosh shumë kohë në shkruan kod për të rregulluar këto të dhëna.

Kemi marrë parasysh disavantazhet dhe kuptuam se na duhej të kalonim në diçka më të përshtatshme, me transaksione normale dhe më pak varësi nga latency. Kemi bërë hulumtime, analizuar shumë opsione dhe kemi zgjedhur PostgreSQL.

Po kalojmë në bazën e të dhënave të re për më shumë se 1.5 vjet dhe kemi zhvendosur vetëm një pjesë të vogël të të dhënave, prandaj tani punojmë njëkohësisht me Redis dhe PostgreSQL. Më shumë rreth fazave të kalimit dhe kalimit të të dhënave midis bazave të të dhënave është shkruar në artikulën e kolegut tim.

Kur sapo filluam të kalojmë, aplikacioni ynë punonte drejtpërdrejt me bazën e të dhënave dhe i drejtohej masterit të Redis dhe PostgreSQL. Klusteri PostgreSQL përbëhej nga një master dhe një replikë me replikim asinkron. Kjo ishte skema e punës me bazat:
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Zbatimi i PgBouncer

Ndërsa po lëviznim, produkti gjithashtu po zhvillohej: numri i përdoruesve dhe serverëve që punonin me PostgreSQL po rritej, dhe na duhej më shumë lidhje. PostgreSQL krijon një proces të veçantë për çdo lidhje dhe konsumon burime. Rritja e numrit të lidhjeve mund të bëhet deri në një pikë të caktuar, përndryshe ka rrezik për performancën jo optimale të DB. Zgjedhja ideale në një situatë të tillë do të ishte një menaxher lidhjesh, i cili do të vendoset para bazës së të dhënave.

Ne kishim dy opsione për menaxherin e lidhjeve: Pgpool dhe PgBouncer. Por i pari nuk mbështet modalitetin transaksional të punës me bazën, ndaj zgjodhëm PgBouncer.

Ne konfiguram skemën e mëposhtme të punës: aplikacioni ynë i qaset një PgBouncer, pas të cilit ndodhen masterat e PostgreSQL, dhe për çdo master ka një replikë me replikim asinkron.
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Kjo situatë na bëri të pamundshme që të ruajmë të gjithë volumet e të dhënave në PostgreSQL, dhe për ne ishte e rëndësishme shpejtësia e punës me bazën, prandaj filluam të shardojmë PostgreSQL në nivelin aplikativ. Schemi i përshkruar më sipër është relativisht i përshtatshëm për këtë: kur shtohet një shard i ri, mjafton të përditësohet konfigurimi i PgBouncer dhe aplikacioni mund të fillojë menjëherë të punojë me shard-in e ri.

Qëndrueshmëria e PgBouncer

Ky skemë vazhdoi deri në momentin kur instanca e vetme e PgBouncer-u vdiq. Ne jemi në AWS, ku të gjitha instancat janë të vendosura në harduer që vdes herë pas here. Në raste të tilla, instancat thjesht kalojnë në harduer të ri dhe fillojnë sërish punën. Kështu ndodhi edhe me PgBouncer, megjithëse ai u bë i paafërt. Si rezultat i kësaj rënie, shërbimi ynë ishte i paafërt për 25 minuta. AWS për këto situata rekomandon përdorimin e ndihmës nga ana e përdoruesit, që nuk ishte realizuar nga ne atëherë.

Pas kësaj, ne u menduam seriozisht për qëndrueshmërinë e PgBouncer-it dhe klastereve të PostgreSQL, sepse një situatë e ngjashme mund të përsëritet me çdo instancë në llogarinë tonë AWS.

Ne kemi ndërtuar një skemë të besueshme PgBouncer si më poshtë: të gjitha serverat e aplikacionit lidheshin me Network Load Balancer, pas të cilit qëndrojnë dy PgBouncer. Secili PgBouncer monitoron të njëjtat master PostgreSQL të çdo sharde. Në rast se ndodh sërish rënia e instancës së AWS, të gjitha trafiku do të redirektohet përmes PgBouncer tjetër. Qëndrueshmëria e Network Load Balancer sigurohet nga AWS.

Kjo skemë lejon të shtoni servera të rinj PgBouncer pa probleme.
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Krijimi i një kluzeri PostgreSQL të besueshëm

Kur po zgjidhnim këtë problem, ne shqyrtuam opsione të ndryshme: failover të shkruara vetë, repmgr, AWS RDS, Patroni.

Skemat e shkruara vetë

Mund të monitorojnë funksionimin e master-it dhe, në rast rënie, të promovojnë replikën në master dhe të përditësojnë konfigurimin e PgBouncer.

Avantazhi i këtij qasjeje është maximumi i thjeshtë, sepse ju shkruani skemat tuaj dhe e kuptoni saktësisht se si funksionojnë ato.

Disavantazhet:

  • Masteri nuk mund të ishte ndarë, por mund të kishte pasur një defekt në rrjet. Failover, pa e ditur këtë, do të avancojë replikën deri te masteri, ndërsa masteri i vjetër do të vazhdojë të punojë. Si rezultat, do të kemi dy servers në rol master dhe nuk do të dimë se në cilin prej tyre janë të dhënat më të fundit. Një situatë të tillë e quajnë gjithashtu split-brain;
  • Kemi mbetur pa replikë. Në konfigurimin tonë kemi një master dhe një replikë, pas kalimit replikat avancojnë deri te masteri dhe nuk kemi më replika, kështu që na duhet të shtojmë manualisht një replikë të re;
  • Na nevojitet monitorim shtesë për funksionimin e failover-it, për këtë kemi 12 sharda PostgreSQL, që do të thotë se duhet të monitorojmë 12 klasterë. Me rritjen e numrit të shardeve, duhet të mos harrojmë të përditësojmë gjithashtu edhe failover-in.

Failover-i i shkruar në mënyrë manuale duket shumë i komplikuar dhe kërkon mbështetje jo triviale. Me një klaster PostgreSQL, kjo do të ishte opsioni më i thjeshtë, por nuk është i shkallëzuar, prandaj nuk na përshtatet.

Repmgr

Replication Manager për grupe PostgreSQL, i cili di të menaxhojë punën e grupit PostgreSQL. Megjithatë, nuk ka një automatik përfailje "jashtë kutisë", prandaj do të nevojitet të shkruani një "mbështjellës" mbi zgjidhjen e gatshme. Kështu që gjithçka mund të jetë edhe më e komplikuar se me skenarët e shkruar vetë, prandaj ne as që e provuam Repmgr.

AWS RDS

Mbështet gjithçka që na nevojitet, di të bëjë kopje rezervë dhe mbështet grupin e lidhjeve. Ka një kalim automatik: kur ndërron masteri, riplika bëhet masteri i ri dhe AWS ndryshon regjistrimin DNS në masterin e ri, ndërkohë që replikat mund të ndodhen në AZ të ndryshme.

Siç të metë mund të përmendim mungesën e konfigurimeve të detajuara. Si një shembull i konfigurimeve të detajuara: në instancat tona ka kufizime për lidhjet TCP, çka fatkeqësisht nuk mund të realizohet në RDS:

net.ipv4.tcp_keepalive_time=10
net.ipv4.tcp_keepalive_intvl=1
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_retries2=3

Përveç kësaj, çmimi i AWS RDS është gati dy herë më i lartë se çmimi normal i instancës, që ishte arsyeja kryesore për të hequr dorë nga kjo zgjidhje.

Patroni

Ky është një model në Python për menaxhimin e PostgreSQL me dokumentacion të mirë, automatik përfailje dhe kod burimi në GitHub.

Avantazhet e Patroni:

  • Çdo parametr i konfigurimit është i detajuar, duke shpjeguar si funksionon çdo gjë;
  • Failover automatik punon nga kutia;
  • I shkruar në Python, dhe duke qenë se ne po shkruajmë shumë në Python, do na jetë më e lehtë të merremi me problemet dhe ndoshta madje të ndihmojmë në zhvillimin e projektit;
  • Menaxhon plotësisht PostgreSQL, lejon ndryshimin e konfiguracionit menjëherë në të gjitha nodet e klasterit, dhe nëse për të zbatuar konfigurimin e ri kërkohet ri-nisja e klasterit, atëherë mund ta bëjmë përsëri me ndihmën e Patroni.

Disavantazhet:

  • Nga dokumentacioni nuk është e qartë si të punosh saktësisht me PgBouncer. Megjithatë, është e vështirë ta quash këtë si një minus, sepse detyra e Patroni është të menaxhojë PostgreSQL, dhe si do të kalojnë lidhjet me Patroni — është problemi ynë;
  • Ka pak shembuj të implementimit të Patroni në volumen të madh, ndërsa ka shumë shembuj të implementimit nga e para.

Në fund, për krijimin e një klasteri të qëndrueshëm, ne zgjodhëm pikërisht Patroni.

Procesi i implementimit të Patroni

Para Patroni kishim 12 sharded PostgreSQL në konfigurimin një master dhe një replikë me replikim asinkron. Serverët e aplikacioneve lidhen me bazat e të dhënave përmes Network Load Balancer, pas të cilit ishin dy instance me PgBouncer, dhe pas tyre ndodheshin të gjithë serverët PostgreSQL.
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Për të implementuar Patroni, na duhej të zgjidhim një ruajtje të shpërndarë për konfigurimin e klasterit. Patroni punon me sisteme të shpërndara për ruajtjen e konfigurimeve, të tilla si etcd, Zookeeper, Consul. Ne kemi një klaster të plotë Consul në prodhim, i cili funksionon në lidhje me Vault, dhe përndryshe nuk e përdorim. Një mundësi e shkëlqyer për të filluar ta përdorim Consul për qëllimin e tij.

Si funksionon Patroni me Consul

Ne kemi një klaster Consul, i cili përbëhet nga tre node dhe një klaster Patroni, i cili përbëhet nga një lider dhe një replikë (në Patroni, masteri quhet lider klasteri, ndërsa skllavët quhen replika). Çdo instancë e klasterit Patroni vazhdimisht dërgon në Consul informacion mbi gjendjen e klasterit. Prandaj, nga Consul gjithmonë mund të mësojmë konfigurimin aktual të klasterit Patroni dhe se kush është lideri në këtë moment.

Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Për të lidhur Patroni me Consul, mjafton të studiojmë dokumentacionin zyrtar, ku thuhet se duhet të tregojmë hostin në formatin http ose https, varësisht se si punojmë me Consul, dhe skemën e lidhjes, opsionale:

host: host:port për pikën e fundit Consul, në formatin: http(s)://host:port
scheme: (opsionale) http ose https, me parazgjedhje http

Duket e thjeshtë, por këtu fillojnë problemet kapitale. Me Consul ne punojmë përmes një lidhjeje të sigurt përmes https dhe konfigurimi ynë i lidhjes do të duket si më poshtë:

consul:
  host: https://server.production.consul:8080 
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

Por nuk funksionon kështu. Gjatë nisjes, Patroni nuk mund të lidhet me Consul, sepse përpiqet të shkojë ende përmes http.

Të kuptosh problemin ndihmoi kodi burimor i Patroni. Është mirë që është shkruar në python. Duket se parametri host nuk analizoi asnjëherë, dhe protokolli duhet të specifikohet në scheme. Kështu duket blloku i punës konfigurues për të punuar me Consul tek ne:

consul:
  host: server.production.consul:8080
  scheme: https
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

Consul-template

Pra, kemi zgjedhur magazinën për konfigurim. Tani duhet të kuptojmë se si PgBouncer do të kalojë konfigurimin e tij kur të ndryshojë lideri në klasterin Patroni. Në dokumentacionin për këtë pyetje nuk ka përgjigje, sepse aty nuk është përshkruar puna me PgBouncer në thelb.

Në kërkim të një zgjidhjeje, gjetëm një artikull (emri, për fat të keq, nuk më vjen në mendje), ku ishte shkruar se Consul-template ndihmonte shumë në lidhjen midis PgBouncer dhe Patroni. Kjo na nxit të studiojmë punën e Consul-template.

Doli, që Sonsul-template monitoron vazhdimisht konfigurimin e klasterit PostgreSQL në Sonsul. Kur ndalon lideri, ajo përditëson konfigurimin e PgBouncer dhe dërgon një komandë për ta rinisur atë.

Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Një përfitim i madh i template është se ai ruhet si kod, prandaj kur shtohet një shard i ri, mjafton të bëhet një komit i ri dhe të përditësohet template në mënyrë automatike, duke mbështetur parimin e Infrastrukturës si Kod.

Arkitektura e re me Patroni

Si rezultat, ne morëm këtë skemë pune:
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Të gjitha serverat e aplikacionit i drejtohen balancuesit → pas tij qëndrojnë dy instance PgBouncer → në çdo instance është e aktivizuar Sonsul-template, e cila monitoron gjendjen e çdo klasteri Patroni dhe kontrollon aktualitetin e konfigurations së PgBouncer, e cila dërgon kërkesat te lideri aktual i çdo klasteri.

Testimi manual

Këtë skemë para lëshimit në prodhim, e kemi drejtuar në një ambient të vogël testimi dhe kemi verifikuar funksionimin e kalimit automatizuar. Hapëm tabelën, lëvizëm sticker-in dhe në atë moment “vritnim” liderin e klasterit. Në AWS, për këtë mjafton të fiket instance përmes konsolës.

Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Stickeri u rikthej brenda 10-20 sekondave, dhe pastaj filloi përsëri të lëvizë normalisht. Kështu që, klasteri Patroni ka funksionuar siç duhet: ndëroi liderin, dërgoi informacionin në Consul, dhe Consul-template e kap atë informacion menjëherë, zëvendësoi konfigurimin e PgBouncer dhe dërgoi komandën për reload.

Si të mbijetosh nën ngarkesë të lartë dhe të ruash minimumin e kohës së papunësisë?

Punon gjithçka shkëlqyer! Por shfaqen pyetje të reja: Si do të funksionojë nën ngarkesë të lartë? Si të implementojmë gjithçka shpejt dhe sigurt në production?

Për të përgjigjur pyetjes së parë, na ndihmon mjedisi testues, ku bëjmë testimin e ngarkesës. Ai është plotësisht identik me production në arkitekturë dhe ka të dhëna testuese të gjeneruara, që në volum janë përafërsisht të barabarta me produksionin. Ne e zgjidhim thjesht ta "vrasim" një nga masterat e PostgreSQL gjatë testit dhe të shohim se çfarë do të ndodhë. Por para kësaj, është e rëndësishme të kontrollojmë automatizimin e roll-out-it, sepse në këtë mjedis kemi disa shard-e PostgreSQL, kështu që do të marrim një testim të shkëlqyer të skripteve konfigurimi para produksionit.

Të dyja detyrat duken ambicioze, por ne kemi PostgreSQL 9.6. Ndoshta mund të azhurnohemi direkt në 11.2?

Ne jemi duke vendosur ta bëjmë këtë në 2 etapa: së pari të përditësojmë versionin në 11.2, pastaj të nisim Patroni.

Përditësimi i PostgreSQL

Për një përditësim të shpejtë të versionit të PostgreSQL, duhet të përdorni opsionin -k, në të cilin krijohen hard link-e në disk dhe nuk ka nevojë për kopjimin e të dhënave tuaja. Në bazat mbi 300-400 GB, përditësimi zgjat 1 sekondë.

Kemi shumë shard-e, prandaj duhet ta bëjmë përditësimin në mënyrë automatike. Për këtë kemi shkruar një Ansible playbook, që realizon të gjithë procesin e përditësimit për ne:

/usr/lib/postgresql/11/bin/pg_upgrade 
<b>--link </b>
--old-datadir='' --new-datadir='' 
 --old-bindir=''  --new-bindir='' 
 --old-options=' -c config_file=' 
 --new-options=' -c config_file='

Këtu është e rëndësishme të theksohet se para se të nisim përmirësimin, duhet ta realizojmë atë me parametrin —check, për të qenë të sigurt për mundësinë e përmirësimit. Po ashtu, skenari ynë bën zëvendësimin e konfigurimeve për kohën e përditësimit. Skenari ynë u ekzekutua për 30 sekonda, rezultat i shkëlqyer.

Nisja e Patroni

Për të zgjidhur problemin e dytë, mjafton të shikoni konfigurimin e Patroni. Në depozitën zyrtare ka një shembull konfigurimi me initdb, që është përgjegjës për inicializimin e një baze të re gjatë nisjes së parë të Patroni. Por pasi kemi një bazë të përfunduar, thjesht e hoqëm këtë seksion nga konfigurimi.

Kur filluam të vendosnim Patroni në një klaster PostgreSQL të gatshëm dhe ta nisim atë, u përballëm me një problem të ri: të dy serverat fillonin si liderë. Patroni nuk di asgjë për gjendjen e mëparshme të klasterit dhe përpiqet të niste të dy serverat si dy klasterë të veçantë me të njëjtin emër. Për të zgjidhur këtë problem, është e nevojshme të fshini direktoriumin me të dhëna në slave:

rm -rf /var/lib/postgresql/

Kjo duhet bërë vetëm në slave!

Kur lidhet një replikë e pastër, Patroni bën një basebackup të liderit dhe e rikthen atë në replikë, më pas përditëson gjendjen aktuale përmes wal-loga.

Një vështirësi tjetër me të cilën u përballëm është se të gjitha klasterët PostgreSQL përfundimisht quhen main. Kur çdo klaster nuk di asgjë për tjetrin, është në rregull. Por kur dëshironi të përdorni Patroni, të gjithë klasterët duhet të kenë një emër unik. Zgjidhja është të ndryshoni emrin e klasterit në konfigurimin e PostgreSQL.

Testi i ngarkesës

Ne kemi lansuar një test që imiton punën e përdoruesve në tabela. Kur ngarkesa arriti mesataren tonë të përditshme, ne përsëritëm të njëjtin test, e ndaluam një instancë me liderin PostgreSQL. Failover-i automatik funksionoi ashtu siç prisnim: Patroni ndryshoi liderin, Konsul-template përditësoi konfigurimin e PgBouncer dhe dërgoi urdhrin për ri-ngarkim. Nga grafikat tonë në Grafana, dallohej që kishte vonesa prej 20-30 sekondash dhe disa gabime të vogla nga serverët lidhur me lidhjen me bazën e të dhënave. Kjo është një situatë normale, këto vlera janë të pranueshme për failover-in tonë dhe sigurisht më të mira se ndalimi i shërbimit.

Doli Patroni në prodhim

Në fund, plani ynë është si në vijim:

  • Deploy Konsul-template në serverat PgBouncer dhe nisja;
  • Përditësimi i PostgreSQL në versionin 11.2;
  • Ndryshimi i emrit të klasterit;
  • Nisja e klasterit Patroni.

Në këtë mënyrë, skema jonë lejon që pika e parë të bëhet në çdo kohë, mund të heqim një nga çdo PgBouncer dhe të kryejmë deploy-in dhe nisjen e consul-template. Kështu bëjmë.

Për një implementim të shpejtë, ne përdorëm Ansible, pasi të gjitha playbook-t i kishim testuar tashmë në mjedisin e provës, dhe koha e ekzekutimit të skenarit të plotë varionte nga 1.5 deri në 2 minuta për secilin shard. Ne mund të ishim në gjendje të implementonim secilin shard një nga një pa ndalur shërbimin tonë, por do të na duhej të ndalonim për disa minuta secilin PostgreSQL. Në këtë rast, përdoruesit, të cilët kishin të dhëna në këtë shard, nuk do të ishin në gjendje të punonin plotësisht në këtë kohë, dhe kjo është e papranueshme për ne.

Zgjidhja për këtë situatë ishte një mirëmbajtje e planifikuar, e cila zhvillohet çdo 3 muaj. Ky është një interval për punët e planifikuara, kur ne e ndalim krejtësisht shërbimin tonë dhe përditësojmë instancat e bazës së të dhënave. Një javë para intervalit të ardhshëm, ne vendosëm të prisnim dhe të përgatitemi më mirë. Gjatë këtij kohëprerje, ne morëm masa të tjera sigurie: për secilin shard PostgreSQL ngritëm një replikë rezervë në rast të dështimeve, për të ruajtur të dhënat më të fundit, dhe shtuam një instancë të re për secilin shard, e cila do të bëhej një replikë e re në klasterin Patroni, për të shmangur ekzekutimin e komandës për fshirjen e të dhënave. Të gjitha këto ndihmuan në minimizimin e rrezikut të gabimeve.
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Ne kemi rivendosur shërbimin tonë; gjithçka funksionoi siç duhet, përdoruesit vazhduan të punojnë, por në grafikun tonë vërejtëm një ngarkesë anormalisht të lartë në serverët Consul.
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Pse nuk e pamë këtë në mjedisin testues? Ky problem ilustron shumë mirë se sa e nevojshme është të ndiqet principi Infrastructure as code dhe të përmirësohet e gjithë infrastruktura, duke filluar nga mjediset testuese dhe duke përfunduar me prodhimin. Në të kundërt, është shumë e lehtë të përballesh me një problem të tillë siç patëm ne. Çfarë ndodhi? Konsul fillimisht u shfaq në prodhim dhe më pas në mjediset testuese; përfundimisht, në mjediset testuese versioni Consul ishte më i lartë se në prodhim. Pikërisht në një nga lëshimet ishte zgjidhur rrjedhja e CPU-së gjatë punës me consul-template. Prandaj ne thjesht përditësuam Consul, duke zgjidhur kështu problemin.

Rivendosni klustërin Patroni

Megjithatë, ne patëm një problem të ri, për të cilin as që e dyshonim. Gjatë përditësimit të Consul, ne thjesht e fshijmë nodën e Consul nga klustëri duke përdorur komandën consul leave → Patroni lidhet me një server tjetër Consul → gjithçka funksionon. Por kur arritëm në instancën e fundit të klustrit Consul dhe i dërguam komandën consul leave, të gjithë klustërit Patroni thjesht u rivendosën, dhe në logje pamë gabimin e mëposhtëm:

KALIM: get_cluster
Gjetja (telefononi i fundit):
...
RetryFailedError: 'Kalim i arritur i skaduar'
KALIM: Gabim në komunikim me DCS
<b>LOG: sistemi i bazës së të dhënave është mbyllur</b>

Klleri Patroni nuk mundi të merrte informacionin për klusterin e tij dhe u rindez.

Për të gjetur një zgjidhje, ne u drejtuam te autorët e Patronit përmes një çështjeje në github. Ata sugjeruan përmirësime në skedarët tanë të konfigurimit:

consul:
 consul.checks: []
bootstrap:
 dcs:
   retry_timeout: 8

Ne arritëm ta përsërisim problemin në mjedisin testues dhe e testuam atje këto parametra, por fatkeqësisht, ato nuk funksionuan.

Problemi ende mbetet i pazgjidhur. Ne planifikojmë të provojmë opsione të tjera për zgjidhje:

  • Të përdorim agentin Consul në çdo instancë të klasterit Patroni;
  • Të rregullojmë problemin në kod.

Na është e qartë vendi i shfaqjes së gabimit: me siguri, problemi është në përdorimin e default timeout, i cili nuk ripërcaktohet përmes skedarit të konfigurimit. Kur heqim serverin e fundit të Consul nga klusteri, ndodh ngrirja e tërë klusterit Consul, e cila zgjat më shumë se një sekondë, dhe për këtë arsye Patroni nuk mund të marrë gjendjen e klasterit dhe e rindez tërë klasterin.

Për fat të mirë, nuk hasëm më ndonjë gabim tjetër.

Përfundimet e përdorimit të Patronit

Pas pastrimit të suksesshëm të Patroni, ne kemi shtuar një replikë shtesë në secilin klaster. Tani, në çdo klaster ka një lloj kuorumi: një lider dhe dy replika, për të siguruar mbështetje në rast të ndarjes së mendimeve gjatë kalimit.
Klastri i besëzëshëm PostgreSQL + Patroni. Eksperiencë e implementimit

Në prodhim, Patroni ka funksionuar për më shumë se tre muaj. Gjatë kësaj kohe, ai ka ndihmuar tashmë. Së fundmi, lideri i një prej klashtave vdiq në AWS, dhe automatikisht ndodhi failover dhe përdoruesit vazhduan të punonin. Patroni realizoi detyrën e tij kryesore.

Një përmbledhje e përdorimit të Patroni:

  • Lehtësia e ndryshimit të konfiguracionit. Bëhet e mjaftueshme të ndryshoni konfiguracionin në një instancë dhe ajo do t’u transmetohet tërë klashtit. Nëse kërkohet rinisja për të zbatuar konfiguracionin e ri, atëherë Patroni do ta njoftojë për këtë. Patroni mund të rinisë tërë klashtin me një komandë, që gjithashtu është shumë e përshtatshme.
  • Automatikisht ndodhi failover dhe tashmë ka ndihmuar.
  • Përditësimi i PostgreSQL pa ndonjë kohë të mbylljes së aplikacionit. Fillimisht, nevojitet të përditësohen replikat në versionin e ri, pastaj të ndryshohet lideri në klasterin e Patroni dhe të përditësohet lideri i vjetër. Gjatë kësaj, bëhet testimi i nevojshëm i automatikisht ndodhur të failover.

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster