Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Vă sugerez să citiți transcrierea raportului de la începutul anului 2016 de Andrey Salnikov „Erori tipice în aplicații care duc la balonare în postgresql”

În acest raport voi analiza principalele erori în aplicații care apar în etapa de proiectare și scriere a codului aplicației. Și voi lua numai acele erori care duc la balonare în Postgresql. De regulă, acesta este începutul sfârșitului performanței sistemului dvs. în ansamblu, deși inițial nu erau vizibile condiții preliminare pentru aceasta.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Mă bucur să îi urez bun venit tuturor! Acest raport nu este la fel de tehnic ca cel anterior de la colegul meu. Acest raport se adresează în principal dezvoltatorilor de sisteme backend, deoarece avem un număr destul de mare de clienți. Și toți fac aceleași greșeli. O să vă povestesc despre ele. Voi explica la ce lucruri fatale și rele duc aceste greșeli.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

De ce se fac greșeli? Se fac din două motive: la întâmplare, poate că va funcționa și din cauza necunoașterii unor mecanisme care apar la nivelul dintre baza de date și aplicație, precum și în baza de date în sine.

Îți voi da trei exemple cu imagini groaznice despre cât de rău au ajuns lucrurile. Vă voi spune pe scurt despre mecanismul care se întâmplă acolo. Și cum să le faci față, când s-au întâmplat și ce metode preventive să folosești pentru a preveni greșelile. Vă voi spune despre instrumentele auxiliare și vă voi oferi link-uri utile.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Am folosit o bază de date de testare în care aveam două tabele. O placă cu conturile clienților, cealaltă cu tranzacții pe aceste conturi. Și cu o oarecare frecvență actualizăm soldurile acestor conturi.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Datele inițiale ale plăcii: este destul de mică, 2 MB. Timpul de răspuns pentru baza de date și în special pentru semn este, de asemenea, foarte bun. Și o încărcătură destul de bună - 2 de operații pe secundă conform plăcuței.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și prin acest raport vă voi arăta grafice, astfel încât să înțelegeți clar ce se întâmplă. Vor fi întotdeauna 2 diapozitive cu grafice. Primul slide este ceea ce se întâmplă în general pe server.

Și în această situație, vedem că avem într-adevăr un mic semn. Indicele este mic la 2 MB. Acesta este primul grafic din stânga.

Timpul mediu de răspuns pe server este, de asemenea, stabil și scurt. Acesta este graficul din dreapta sus.

Graficul din stânga jos arată cele mai lungi tranzacții. Vedem că tranzacțiile sunt finalizate rapid. Și autovacuum-ul nu funcționează încă aici, pentru că a fost un test de pornire. Va continua să funcționeze și ne va fi de folos.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Al doilea slide va fi întotdeauna dedicat plăcii testate. În această situație, actualizăm constant soldurile contului clientului. Și vedem că timpul mediu de răspuns pentru o operațiune de actualizare este destul de bun, mai puțin de o milisecundă. Vedem că resursele procesorului (acesta este graficul din dreapta sus) sunt, de asemenea, consumate uniform și destul de mici.

Graficul din dreapta jos arată câtă memorie de operare și de disc trecem în căutarea liniei dorite înainte de a o actualiza. Iar numărul de operații conform semnului este de 2 pe secundă, așa cum am spus la început.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și acum avem o tragedie. Din anumite motive, există o tranzacție uitată de mult. Motivele sunt de obicei banale:

  • Una dintre cele mai frecvente este că am început să accesăm un serviciu extern în codul aplicației. Și acest serviciu nu ne răspunde. Adică am deschis o tranzacție, am făcut o modificare în baza de date și am trecut de la aplicație la citirea e-mailurilor sau la un alt serviciu din infrastructura noastră și din anumite motive nu ne răspunde. Și sesiunea noastră este blocată într-o stare în care nu se știe când va fi rezolvată.
  • A doua situație este atunci când a apărut o excepție în codul nostru dintr-un motiv oarecare. Și în excepție nu am procesat închiderea tranzacției. Și am ajuns la o sesiune de suspendare cu o tranzacție deschisă.
  • Și ultimul este, de asemenea, un caz destul de comun. Acesta este un cod de calitate scăzută. Unele cadre deschid o tranzacție. Se blochează și este posibil să nu știți în aplicație că îl aveți suspendat.

Unde duc astfel de lucruri?

Până în punctul în care tabelele și indicii încep să se umfle dramatic. Acesta este exact același efect de balonare. Pentru baza de date, acest lucru va însemna că timpul de răspuns al bazei de date va crește foarte brusc, iar sarcina pe serverul bazei de date va crește. Și, ca urmare, aplicația noastră va avea de suferit. Pentru că dacă ai cheltuit 10 milisecunde în codul tău pentru o solicitare către baza de date, 10 milisecunde pe logica ta, atunci funcția ta a durat 20 de milisecunde pentru a fi finalizată. Și acum situația ta va fi complet tristă.

Și să vedem ce se întâmplă. Graficul din stânga jos arată că avem o tranzacție lungă. Și dacă ne uităm la graficul din stânga sus, vedem că dimensiunea tabelului nostru a sărit brusc de la doi megaocteți la 300 de megaocteți. În același timp, cantitatea de date din tabel nu s-a schimbat, adică există o cantitate destul de mare de gunoi acolo.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Situația generală privind timpul mediu de răspuns al serverului s-a schimbat și ea cu câteva ordine de mărime. Adică, toate solicitările de pe server au început să scadă complet. Și în același timp, procesele interne Postgres au fost lansate sub formă de autovacuum, care încearcă să facă ceva și consumă resurse.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Ce se întâmplă cu semnul nostru? Aceeași. Timpul nostru mediu de răspuns în funcție de semn a crescut cu câteva ordine de mărime. Mai exact în ceea ce privește resursele consumate, vedem că sarcina procesorului a crescut foarte mult. Acesta este graficul din dreapta sus. Și a crescut pentru că procesorul trebuie să sorteze o grămadă de linii inutile în căutarea celei necesare. Acesta este graficul din dreapta jos. Și, ca urmare, numărul nostru de apeluri pe secundă a început să scadă foarte semnificativ, deoarece baza de date nu a avut timp să proceseze același număr de solicitări.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Trebuie să ne întoarcem la viață. Intrăm online și aflăm că tranzacțiile lungi duc la probleme. Găsim și omorâm această tranzacție. Și totul devine normal pentru noi. Totul funcționează așa cum ar trebui.

Ne-am liniștit, dar după un timp începem să observăm că aplicația nu funcționează la fel ca înainte de urgență. Solicitările sunt încă procesate mai lent și semnificativ mai lent. O dată și jumătate până la două ori mai lent, în special în exemplul meu. Sarcina de pe server este, de asemenea, mai mare decât era înainte de accident.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și întrebarea: „Ce se întâmplă cu baza în acest moment?” Și următoarea situație apare cu baza. Pe graficul tranzacțiilor puteți vedea că s-a oprit și că nu există tranzacții pe termen lung. Dar dimensiunea semnului a crescut fatal în timpul accidentului. Și de atunci nu au mai scăzut. Timpul mediu pe bază s-a stabilizat. Iar răspunsurile par să vină în mod adecvat cu o viteză acceptabilă pentru noi. Aspiratorul automat a devenit mai activ și a început să facă ceva cu semnul, deoarece trebuie să verifice mai multe date.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Mai exact, conform plăcuței de testare cu conturi, unde schimbăm soldurile: timpul de răspuns la o solicitare pare să fi revenit la normal. Dar în realitate este de o ori și jumătate mai mare.

Și din încărcarea procesorului, vedem că încărcarea procesorului nu a revenit la valoarea necesară înainte de accident. Iar motivele se află tocmai în graficul din dreapta jos. Se poate observa că acolo se caută o anumită cantitate de memorie. Adică, pentru a găsi linia necesară, irosim resursele serverului de baze de date în timp ce sortăm prin date inutile. Numărul de tranzacții pe secundă s-a stabilizat.

În general bună, dar situația este mai proastă decât era. Degradarea clară a bazei de date ca o consecință a aplicației noastre care funcționează cu această bază de date.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și pentru a înțelege ce se întâmplă acolo, dacă nu ați fost la raportul anterior, acum să luăm puțină teorie. Teoria despre procesul intern. De ce un aspirator auto și ce face?

Literal pe scurt pentru înțelegere. La un moment dat avem o masă. Avem rânduri în tabel. Aceste linii pot fi active, vii și de ce avem nevoie acum. Sunt marcate cu verde în imagine. Și există linii limită care au fost deja rezolvate, au fost actualizate și au apărut noi intrări pe ele. Și sunt marcate că nu mai sunt interesante pentru baza de date. Dar sunt în tabel datorită unei caracteristici Postgres.

De ce ai nevoie de un aspirator auto? Autovacuum vine la un moment dat, accesează baza de date și o întreabă: „Vă rog să-mi dați id-ul celei mai vechi tranzacții care este deschisă în prezent în baza de date”. Baza de date returnează acest id. Iar aspiratorul automat, bazându-se pe el, sortează liniile din tabel. Și dacă vede că unele linii au fost modificate de tranzacții mult mai vechi, atunci are dreptul să le marcheze drept linii pe care le putem refolosi în viitor scriind acolo date noi. Acesta este un proces de fundal.

În acest moment, continuăm să lucrăm cu baza de date și continuăm să facem unele modificări în tabel. Și pe aceste rânduri, pe care le putem reutiliza, scriem date noi. Și astfel obținem un ciclu, adică tot timpul acolo apar niște linii vechi moarte, în loc de ele scriem linii noi de care avem nevoie. Și aceasta este o stare normală pentru ca PostgreSQL să funcționeze.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Ce s-a întâmplat în timpul accidentului? Cum s-a întâmplat acest proces acolo?

Aveam un semn într-o anumită stare, unele vii, unele linii moarte. A sosit aspiratorul mașinii. A întrebat baza de date care este cea mai veche tranzacție a noastră și care este id-ul acesteia. Am primit acest id, care ar putea fi acum multe ore, poate acum zece minute. Depinde de cât de grea este sarcina pe care o ai pe baza de date. Și a mers să caute linii pe care le-ar putea marca ca fiind refolosite. Și nu am găsit astfel de linii în tabelul nostru.

Dar în acest moment continuăm să lucrăm cu masa. Facem ceva în el, îl actualizăm, schimbăm datele. Ce ar trebui să facă baza de date în acest moment? Nu are de ales decât să adauge linii noi la sfârșitul tabelului existent. Și astfel dimensiunea mesei noastre începe să se umfle.

În realitate, avem nevoie de linii verzi pentru a funcționa. Dar în timpul unei astfel de probleme, se dovedește că procentul de linii verzi este extrem de scăzut pe întregul tabel.

Iar atunci când executăm o interogare, baza de date trebuie să treacă prin toate liniile: atât roșii cât și verzi, pentru a găsi linia dorită. Iar efectul balonării unui tabel cu date inutile se numește „balonare”, care ne consumă și spațiul pe disc. Ține minte, a fost 2 MB, a devenit 300 MB? Acum schimbați megaocteții în gigaocteți și veți pierde rapid toate resursele de disc.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Ce consecințe ar putea fi pentru noi?

  • În exemplul meu, tabelul și indicele au crescut de 150 de ori. Unii dintre clienții noștri au avut mai multe cazuri fatale când pur și simplu au început să rămână fără spațiu pe disc.
  • Dimensiunea meselor în sine nu va scădea niciodată. În unele cazuri, aspirarea automată poate tăia coada mesei dacă există doar linii moarte. Dar, deoarece există o rotație constantă, o linie verde se poate îngheța la sfârșit și nu poate fi actualizată, în timp ce toate celelalte vor fi notate undeva la începutul plăcii. Dar acesta este un eveniment atât de puțin probabil încât masa dvs. în sine se va micșora în dimensiune, așa că nu ar trebui să sperați la el.
  • Baza de date trebuie să sorteze printr-o grămadă de linii inutile. Și risipim resursele de disc, risipim resursele procesorului și energie electrică.
  • Și acest lucru afectează direct aplicația noastră, deoarece dacă la început am cheltuit 10 milisecunde pe cerere, 10 milisecunde pe codul nostru, atunci în timpul accidentului am început să petrecem o secundă pe cerere și 10 milisecunde pe cod, adică o comandă de amploarea performanței aplicației a scăzut. Și când accidentul a fost rezolvat, am început să petrecem 20 de milisecunde pentru o solicitare, 10 milisecunde pentru un cod. Aceasta înseamnă că încă am scăzut de o dată și jumătate în productivitate. Și totul din cauza unei tranzacții care a înghețat, poate din vina noastră.
  • Și întrebarea: „Cum putem recupera totul?”, astfel încât totul să fie în regulă pentru noi și solicitările să vină la fel de repede ca înainte de accident.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

În acest scop, există un anumit ciclu de lucru care se realizează.

Mai întâi trebuie să găsim tabelele problematice care sunt umflate. Înțelegem că în unele tabele înregistrarea este mai activă, în altele mai puțin activă. Și pentru asta folosim extensia pgstattuple. Prin instalarea acestei extensii, puteți scrie interogări care vă vor ajuta să găsiți tabele care sunt destul de umflate.

Odată ce ați găsit aceste tabele, trebuie să le comprimați. Există deja instrumente pentru asta. În compania noastră folosim trei instrumente. Primul este VACUUM FULL încorporat. Este crud, aspru și fără milă, dar uneori este foarte util. Pg_repack и pgcompacttable - Acestea sunt utilitare terțe pentru comprimarea tabelelor. Și tratează baza de date cu mai multă atenție.

Ele sunt folosite în funcție de ceea ce este mai convenabil pentru tine. Dar vă voi spune despre asta la final. Principalul lucru este că există trei instrumente. Există o mulțime din care să alegeți.

După ce am corectat totul și ne-am asigurat că totul este în regulă, trebuie să știm cum să prevenim această situație pe viitor:

  • Poate fi prevenit destul de ușor. Trebuie să monitorizați durata sesiunilor pe serverul Master. Mai ales sesiuni periculoase în inactivitate în starea tranzacției. Aceștia sunt cei care tocmai au deschis o tranzacție, au făcut ceva și au plecat, sau pur și simplu s-au agățat, s-au pierdut în cod.
  • Și pentru dumneavoastră, ca dezvoltatori, este important să vă testați codul atunci când apar aceste situații. Nu este greu de făcut. Aceasta va fi o verificare utilă. Veți evita un număr mare de probleme „copilești” asociate cu tranzacțiile lungi.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

În aceste grafice, am vrut să vă arăt cum s-au schimbat semnul și comportamentul bazei de date după ce am trecut prin semnul cu VACUUM FULL în acest caz. Aceasta nu este producție pentru mine.

Dimensiunea tabelului a revenit imediat la starea normală de funcționare de câțiva megaocteți. Acest lucru nu a afectat foarte mult timpul mediu de răspuns pentru server.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Dar, în special pentru semnul nostru de testare, în care am actualizat soldurile conturilor, vedem că timpul mediu de răspuns pentru o solicitare de actualizare a datelor din semn a fost redus la niveluri de dinainte de urgență. Resursele consumate de procesor pentru a finaliza această solicitare au scăzut, de asemenea, la niveluri pre-crash. Iar graficul din dreapta jos arată că acum găsim exact linia de care avem nevoie imediat, fără a trece prin grămezile de linii moarte care erau acolo înainte ca masa să fie comprimată. Și timpul mediu de solicitare a rămas aproximativ la același nivel. Dar aici am, mai degrabă, o eroare în hardware-ul meu.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Aici se termină prima poveste. Este cea mai comună. Și se întâmplă tuturor, indiferent de experiența clientului și de cât de calificați sunt programatorii. Mai devreme sau mai târziu se întâmplă asta.

A doua poveste, în care distribuim încărcarea și optimizăm resursele serverului

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

  • Am crescut deja și am devenit băieți serioși. Și înțelegem că avem o replică și ar fi bine pentru noi să echilibrăm încărcătura: scrie-i Maestrului și citim din replică. Și de obicei această situație apare atunci când vrem să pregătim niște rapoarte sau ETL. Și afacerile sunt foarte încântate de asta. Își dorește cu adevărat o varietate de rapoarte cu o mulțime de analize complexe.
  • Rapoartele durează multe ore, deoarece analizele complexe nu pot fi calculate în milisecunde. Noi, ca băieții curajoși, scriem cod. În aplicația de inserare facem înregistrarea pe Master și executăm rapoartele pe replică.
  • Distribuirea sarcinii.
  • Totul funcționează perfect. Suntem grozavi.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și cum arată această situație? Mai exact pe aceste grafice am adăugat și durata tranzacțiilor din replica pentru durata tranzacției. Toate celelalte grafice se referă numai la serverul Master.

Până atunci, consiliul meu de raport a crescut. Sunt mai mulți. Vedem că timpul mediu de răspuns al serverului este stabil. Vedem că pe replică avem o tranzacție de lungă durată care durează 2 ore. Vedem funcționarea silențioasă a autovacuumului, care procesează liniile moarte. Și totul este în regulă la noi.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Mai exact, conform plăcuței testate, continuăm să actualizăm soldurile conturilor de acolo. Și avem, de asemenea, un timp de răspuns stabil pentru solicitări, consum stabil de resurse. Totul este în regulă la noi.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Totul este în regulă până în momentul în care aceste rapoarte încep să revină din cauza unui conflict cu replicarea. Și trag înapoi la intervale regulate.

Intrăm online și începem să citim de ce se întâmplă acest lucru. Și găsim o soluție.

Prima soluție este creșterea latenței de replicare. Știm că raportul nostru durează 3 ore. Am stabilit întârzierea de replicare la 3 ore. Lansăm totul, dar continuăm să avem probleme cu rapoartele care sunt uneori anulate.

Vrem ca totul să fie perfect. Urcăm mai departe. Și am găsit o setare grozavă pe Internet - hot_standby_feedback. Să-l pornim. Hot_standby_feedback ne permite să reținem autovacuum-ul pe Master. Astfel, scăpăm complet de conflictele de replicare. Și totul funcționează bine pentru noi cu rapoarte.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și ce se întâmplă cu serverul Master în acest moment? Și avem probleme totale cu serverul Master. Acum vedem graficele când am activate ambele setări. Și vedem că sesiunea de pe replica noastră a început cumva să influențeze situația de pe serverul Master. Ea are un efect pentru că a întrerupt aspiratorul automat, ceea ce elimină liniile moarte. Dimensiunea mesei noastre a crescut vertiginos din nou. Timpul mediu de execuție a interogărilor în întreaga bază de date a crescut vertiginos. Aspiratoarele automate s-au strâns puțin.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Mai exact, din farfuria noastră, vedem că și actualizarea datelor de pe el a sărit în cer. Consumul procesorului a crescut în mod similar foarte mult. Trecem din nou printr-un număr mare de replici moarte, inutile. Și timpul de răspuns pentru acest semn și numărul de tranzacții au scăzut.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Cum va arăta dacă nu știm despre ce vorbeam înainte?

  • Începem să căutăm probleme. Dacă am întâmpinat probleme în prima parte, știm că acest lucru se poate datora unei tranzacții îndelungate și mergem la Maestru. Avem o problemă cu Maestrul. Cârnați-l. Se încălzește, medie de încărcare este de aproximativ o sută.
  • Solicitările acolo sunt lente, dar nu vedem nicio tranzacție de lungă durată acolo. Și nu înțelegem care e treaba. Nu înțelegem unde să căutăm.
  • Verificăm echipamentele serverului. Poate raidul nostru s-a prăbușit. Poate stick-ul nostru de memorie este ars. Da, orice se poate întâmpla. Dar nu, serverele sunt noi, totul funcționează bine.
  • Toată lumea rulează: administratorii, dezvoltatorii și directorul. Nimic nu ajută.
  • Și la un moment dat totul începe brusc să se corecteze.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

În acest moment, cererea de pe replica noastră a fost procesată și lăsată. Am primit raportul. Afacerile sunt încă fericite. După cum puteți vedea, semnul nostru a crescut din nou și nu se va micșora. Pe graficul cu sesiuni, am lăsat o bucată din această tranzacție lungă dintr-o replică, astfel încât să puteți estima cât durează până se stabilizează situația.

Sesiunea s-a terminat. Și abia după ceva timp serverul vine mai mult sau mai puțin în ordine. Iar timpul mediu de răspuns pentru solicitările de pe serverul Master revine la normal. Pentru că, în sfârșit, aspiratorul automat are posibilitatea de a curăța și de a marca aceste linii moarte. Și a început să-și facă treaba. Și cât de repede o face, atât de repede ne vom pune în ordine.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Conform tabletei testate, unde actualizăm soldurile conturilor, vedem exact aceeași imagine. Timpul mediu de actualizare a contului se normalizează, de asemenea, treptat. Resursele consumate de procesor sunt de asemenea reduse. Și numărul de tranzacții pe secundă revine la normal. Dar din nou am revenit la normal, nu la fel ca înainte de accident.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

În orice caz, obținem o reducere a performanței, ca în primul caz, de o dată și jumătate până la două ori și uneori mai mult.

Se pare că am făcut totul bine. Distribuiți sarcina. Echipamentul nu este inactiv. Ne-am împărțit cererile după mintea noastră, dar totuși totul a ieșit prost.

  • Nu activați hot_standby_feedback? Da, nu este recomandat să-l porniți fără motive deosebit de întemeiate. Deoarece această răsucire afectează direct serverul Master și suspendă funcționarea autovacuum-ului acolo. Activând-o pe o replică și uitând de ea, poți să-l ucizi pe Master și să ai probleme mari cu aplicația.
  • Creșteți max_standby_streaming_delay? Da, pentru rapoarte, acest lucru este adevărat. Dacă aveți un raport de trei ore și nu doriți ca acesta să se blocheze din cauza conflictelor de replicare, atunci pur și simplu creșteți întârzierea. Un raport pe termen lung nu necesită niciodată date care au ajuns în baza de date chiar acum. Dacă îl aveți timp de trei ore, atunci îl rulați pentru o perioadă de date vechi. Și pentru tine, dacă există o întârziere de trei ore sau o întârziere de șase ore, nu va face nicio diferență, dar vei primi rapoarte în mod constant și nu vei avea probleme cu căderea lor.
  • Desigur, trebuie să controlați sesiunile lungi pe replici, mai ales dacă decideți să activați hot_standby_feedback pe o replică. Pentru că orice se poate întâmpla. Am dat această replică dezvoltatorului pentru ca acesta să testeze cererile. A scris o cerere nebună. El a lansat-o și a plecat să bea ceai, iar noi am primit Maestrul stabilit. Sau poate am pus aplicația greșită acolo. Situațiile sunt variate. Sesiunile pe replici trebuie monitorizate la fel de atent ca pe Master.
  • Și dacă aveți interogări rapide și lungi pe replici, atunci în acest caz este mai bine să le împărțiți pentru a distribui încărcarea. Acesta este un link către streaming_delay. Pentru cele rapide, aveți o replică cu o mică întârziere de replicare. Pentru solicitările de raportare de lungă durată, aveți o replică care poate întârzia cu 6 ore sau o zi. Aceasta este o situație complet normală.

Eliminăm consecințele în același mod:

  • Găsim mese umflate.
  • Și îl comprimăm cu cel mai convenabil instrument care ni se potrivește.

A doua poveste se termină aici. Să trecem la a treia poveste.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

De asemenea, destul de comun pentru noi în care facem migrație.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

  • Orice produs software este în creștere. Cerințele pentru aceasta se schimbă. În orice caz, vrem să ne dezvoltăm. Și se întâmplă că trebuie să actualizăm datele din tabel, și anume să rulăm o actualizare în ceea ce privește migrarea noastră pentru noua funcționalitate pe care o introducem ca parte a dezvoltării noastre.
  • Vechiul format de date nu este satisfăcător. Să presupunem că acum trecem la al doilea tabel, unde am tranzacții pe aceste conturi. Și să spunem că erau în ruble și am decis să creștem precizia și să o facem în copeici. Și pentru aceasta trebuie să facem o actualizare: înmulțiți câmpul cu suma tranzacției cu o sută.
  • În lumea de astăzi, folosim instrumente automate de control al versiunilor bazei de date. Sa spunem Liquibase. Ne înregistrăm migrația acolo. Îl testăm pe baza noastră de teste. Totul e bine. Actualizarea este în curs. Blochează munca pentru o perioadă, dar primim date actualizate. Și putem lansa noi funcționalități în acest sens. Totul a fost testat și verificat. Totul a fost confirmat.
  • Am efectuat lucrări planificate și am efectuat migrarea.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Iată migrația cu actualizarea prezentată în fața ta. Deoarece acestea sunt tranzacțiile din contul meu, placa era de 15 GB. Și din moment ce actualizăm fiecare linie, am dublat dimensiunea tabelului cu actualizarea, pentru că am rescris fiecare linie.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

În timpul migrării, nu am putut face nimic cu această placă, deoarece toate solicitările către ea au fost puse la coadă și au așteptat până la finalizarea acestei actualizări. Dar aici vreau să vă atrag atenția asupra numerelor care se află pe axa verticală. Adică avem un timp mediu de solicitare înainte de migrare de aproximativ 5 milisecunde și încărcarea procesorului, numărul de operațiuni bloc pentru citirea memoriei discului este mai mic de 7,5.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Am efectuat migrarea și am avut din nou probleme.

Migrarea a avut succes, dar:

  • Vechea funcționalitate durează acum mai mult.
  • Masa a crescut din nou în dimensiuni.
  • Sarcina de pe server a devenit din nou mai mare decât înainte.
  • Și, bineînțeles, încă ne refacem funcționalitatea care a funcționat bine, am îmbunătățit-o puțin.

Și aceasta este din nou balonare, care ne ruinează din nou viețile.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Aici demonstrez că tabelul, ca și cele două cazuri anterioare, nu va reveni la dimensiunile anterioare. Încărcarea medie a serverului pare să fie adecvată.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și dacă ne întoarcem la tabelul cu conturi, vom vedea că timpul mediu de solicitare s-a dublat pentru acest tabel. Sarcina procesorului și numărul de linii sortate în memorie au sărit peste 7,5, dar au fost mai mici. Și a sărit de 2 ori în cazul procesoarelor, de 1,5 ori în cazul operațiunilor în bloc, adică am obținut o degradare a performanței serverului. Și ca rezultat - degradarea performanței aplicației noastre. În același timp, numărul de apeluri a rămas aproximativ la același nivel.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Și principalul lucru aici este să înțelegeți cum să faceți corect astfel de migrații. Și trebuie făcute. Facem aceste migrații destul de consecvent.

  • Migrațiile atât de mari nu au loc automat. Trebuie să fie întotdeauna sub control.
  • Este necesară supravegherea de către o persoană cu cunoștințe. Dacă aveți un DBA în echipa dvs., atunci lăsați DBA să o facă. E treaba lui. Dacă nu, atunci lăsați-o pe cea mai experimentată persoană, care știe să lucreze cu baze de date.
  • O nouă schemă a bazei de date, chiar dacă actualizăm o coloană, ne pregătim întotdeauna în etape, adică în avans înainte ca noua versiune a aplicației să fie lansată:
  • Sunt adăugate câmpuri noi în care vom înregistra datele actualizate.
  • Transferăm date din câmpul vechi în câmpul nou în părți mici. De ce facem asta? În primul rând, controlăm întotdeauna procesul acestui proces. Știm că am transferat deja atât de multe loturi și ne-au rămas atât de multe.
  • Iar al doilea efect pozitiv este că între fiecare astfel de lot închidem tranzacția, deschidem unul nou, iar acest lucru permite autovacuum-ului să funcționeze conform plăcii, marcam liniile limită pentru reutilizare.
  • Pentru liniile care vor apărea în timp ce aplicația rulează (mai avem aplicația veche în funcțiune), adăugăm un declanșator care scrie valori noi în câmpuri noi. În cazul nostru, aceasta este înmulțirea cu o sută a vechii valori.
  • Dacă suntem complet încăpățânați și dorim același câmp, atunci după finalizarea tuturor migrărilor și înainte de a lansa o nouă versiune a aplicației, pur și simplu redenumim câmpurile. Celor vechi li se dă un nume inventat, iar noile câmpuri sunt redenumite în cele vechi.
  • Și abia după aceea lansăm o nouă versiune a aplicației.

Și în același timp nu vom avea o balonare și nu vom avea de suferit în ceea ce privește performanța.

Aici se termină a treia poveste.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

https://github.com/dataegret/pg-utils/blob/master/sql/table_bloat.sql

https://github.com/dataegret/pg-utils/blob/master/sql/table_bloat_approx.sql

Și acum puțin mai multe detalii despre instrumentele pe care le-am menționat chiar în prima poveste.

Înainte de a căuta balonare, trebuie să instalați extensia pgstattuple.

Pentru a nu fi nevoit să veniți cu interogări, am scris deja aceste interogări în munca noastră. Le poți folosi. Sunt două cereri aici.

  • Primul durează destul de mult timp să funcționeze, dar vă va arăta valorile exacte ale balonării din tabel.
  • Al doilea funcționează mai repede și este foarte eficient atunci când trebuie să evaluați rapid dacă există sau nu balonare conform tabelului. Și ar trebui să înțelegeți, de asemenea, că balonarea este întotdeauna prezentă într-un tabel Postgres. Aceasta este o caracteristică a modelului său MVCC.
  • Și 20% balonare este normală pentru mese în majoritatea cazurilor. Adică, nu ar trebui să vă faceți griji și să comprimați acest tabel.

Ne-am dat seama cum să identificăm tabelele care sunt umflate cu date inutile.

Acum despre cum să remediați balonarea:

  • Dacă avem o tabletă mică și discuri bune, adică pe o tabletă de până la un gigabyte, este foarte posibil să folosim VACUUM FULL. El va lua un blocaj exclusiv de la tine pe masă pentru câteva secunde și bine, dar va face totul rapid și aspru. Ce face VACUUM FULL? Este nevoie de o blocare exclusivă a tabelului și rescrie rândurile live din mesele vechi în tabelul nou. Și la final îi înlocuiește. Acesta șterge fișierele vechi și le înlocuiește pe cele vechi cu altele noi. Dar, pe durata activității sale, este nevoie de o blocare exclusivă pe masă. Aceasta înseamnă că nu puteți face nimic cu acest tabel: nici să nu scrieți, nici să citiți în el, nici să nu îl modificați. Iar VACUUM FULL necesită spațiu suplimentar pe disc pentru a scrie date.
  • Următorul instrument pg_repack. În principiu, este foarte asemănător cu VACUUM FULL, deoarece rescrie și datele din fișierele vechi în altele noi și le înlocuiește în tabel. Dar, în același timp, nu ia o blocare exclusivă pe masă chiar la începutul activității sale, ci o ia doar în momentul în care are deja date pregătite pentru a înlocui fișierele. Cerințele sale de resurse de disc sunt similare cu cele ale VACUUM FULL. Aveți nevoie de spațiu suplimentar pe disc, iar acest lucru este uneori critic dacă aveți tabele terabyte. Și este destul de amanat de procesor, deoarece funcționează activ cu I/O.
  • A treia utilitate este pgcompacttable. Este mai atent cu resursele pentru că funcționează după principii puțin diferite. Ideea principală a pgcompacttable este că mută toate rândurile live la începutul tabelului folosind actualizări din tabel. Și apoi rulează un vid pe această masă, pentru că știm că avem rânduri vii la început și rânduri moarte la sfârșit. Și vidul în sine taie această coadă, adică nu necesită mult spațiu suplimentar pe disc. Și, în același timp, încă mai poate fi stors din punct de vedere al resurselor.

Totul cu unelte.

Erori tipice în aplicații care duc la balonare în postgresql. Andrei Salnikov

Dacă ți se pare interesant subiectul bloat în ceea ce privește adâncirea în interior, iată câteva link-uri utile:

Am încercat mai mult să arăt o poveste de groază pentru dezvoltatori, pentru că aceștia sunt clienții noștri direcți ai bazelor de date și trebuie să înțeleagă la ce și la ce duc acțiunile. Sper ca am reusit. Vă mulțumim pentru atenție!

întrebări

Multumesc pentru raport! Ai vorbit despre cum poți identifica problemele. Cum pot fi avertizați? Adică am avut o situație în care cererile s-au blocat nu doar pentru că au accesat niște servicii externe. Acestea au fost doar niște îmbinări sălbatice. Au fost niște cereri minuscule, inofensive, care au rămas o zi și apoi au început să facă niște prostii. Adică foarte asemănător cu ceea ce descrii tu. Cum să urmăresc asta? Stați și urmăriți constant care cerere este blocată? Cum poate fi prevenit acest lucru?

În acest caz, aceasta este o sarcină pentru administratorii companiei dvs., nu neapărat pentru DBA.

Sunt administrator.

PostgreSQL are o vizualizare numită pg_stat_activity care arată interogări suspendate. Și poți vedea cât timp stă acolo.

Trebuie să intru și să mă uit la fiecare 5 minute?

Configurați cron și verificați. Dacă aveți o cerere pe termen lung, scrieți o scrisoare și gata. Adică nu trebuie să te uiți cu ochii, poate fi automatizat. Vei primi o scrisoare, reacționezi la ea. Sau poți fotografia automat.

Există motive evidente pentru care se întâmplă acest lucru?

Am enumerat câteva. Alte exemple mai complexe. Și poate exista o conversație pentru o lungă perioadă de timp.

Multumesc pentru raport! Am vrut să clarific despre utilitarul pg_repack. Dacă ea nu face o blocare exclusivă, atunci...

Ea face o blocare exclusivă.

... atunci aș putea pierde date. Aplicația mea nu ar trebui să înregistreze nimic în acest timp?

Nu, funcționează fără probleme cu tabelul, adică pg_repack transferă mai întâi toate liniile live care există. Desigur, acolo are loc un fel de intrare în tabel. El doar aruncă această coadă de cal.

Adică chiar o face până la urmă?

În cele din urmă, el ia o blocare exclusivă pentru a schimba aceste fișiere.

Va fi mai rapid decât VACUUM FULL?

VACUUM FULL, de îndată ce a început, a luat imediat o blocare exclusivă. Și până nu va face totul, nu o va lăsa să plece. Și pg_repack are o blocare exclusivă numai în momentul înlocuirii fișierului. În acest moment nu vei scrie acolo, dar datele nu se vor pierde, totul va fi bine.

Buna ziua! Ai vorbit despre funcționarea unui aspirator de mașină. Era un grafic cu celule de înregistrare roșii, galbene și verzi. Adică galbene – le-a marcat ca șterse. Și, ca rezultat, ceva nou poate fi scris în ele?

Da. Postgres nu șterge linii. Are o asemenea specificitate. Dacă am actualizat o linie, am marcat-o pe cea veche ca ștearsă. Id-ul tranzacției care a schimbat această linie apare acolo și scriem o nouă linie. Și avem sesiuni care le-ar putea citi. La un moment dat devin destul de bătrâni. Și esența modului în care funcționează autovacuum-ul este că trece prin aceste linii și le marchează ca fiind inutile. Și puteți suprascrie datele acolo.

Am înțeles. Dar nu despre asta este întrebarea. Nu am terminat. Să presupunem că avem o masă. Are câmpuri de dimensiune variabilă. Și dacă încerc să introduc ceva nou, pur și simplu s-ar putea să nu se potrivească în celula veche.

Nu, în orice caz întreaga linie este actualizată acolo. Postgres are două modele de stocare a datelor. Selectează din tipul de date. Există date care sunt stocate direct în tabel și există și date tos. Acestea sunt cantități mari de date: text, json. Sunt depozitate în farfurii separate. Și conform acestor tablete, apare aceeași poveste cu balonare, adică totul este la fel. Sunt enumerate doar separat.

Multumesc pentru raport! Este acceptabil să folosiți interogări de expirare a instrucțiunilor pentru a limita durata?

Foarte acceptabil. Folosim asta peste tot. Și din moment ce nu avem propriile noastre servicii, oferim asistență la distanță, avem o varietate destul de mare de clienți. Și toată lumea este complet mulțumită de asta. Adică avem joburi cron care verifică. Durata ședințelor este pur și simplu convenită cu clientul, înainte de care nu suntem de acord. Ar putea fi un minut, ar putea fi 10 minute. Depinde de sarcina de pe bază și de scopul acesteia. Dar toți folosim pg_stat_activity.

Multumesc pentru raport! Încerc să aplic raportul dvs. la aplicațiile mele. Și se pare că începem o tranzacție peste tot și o completăm în mod clar peste tot. Dacă există vreo excepție, atunci are loc în continuare rollback. Și apoi am început să mă gândesc. La urma urmei, este posibil ca tranzacția să nu înceapă în mod explicit. Acesta este probabil un indiciu pentru fată. Dacă doar actualizez o înregistrare, tranzacția va începe în PostgreSQL și se va finaliza numai când conexiunea este deconectată?

Dacă vorbiți acum despre nivelul aplicației, atunci depinde de driverul pe care îl utilizați, de ORM-ul care este utilizat. Există o mulțime de setări acolo. Dacă ați activat commit-ul automat, atunci o tranzacție începe acolo și se închide imediat.

Adică se închide imediat după actualizare?

Depinde de setări. Am numit o setare. Aceasta este confirmarea automată. Este destul de comun. Dacă este activat, atunci tranzacția s-a deschis și s-a închis. Cu excepția cazului în care ați spus în mod explicit „începeți tranzacția” și „terminați tranzacția”, dar pur și simplu ați lansat o solicitare în sesiune.

Buna ziua! Multumesc pentru raport! Să ne imaginăm că avem o bază de date care se umflă și se umflă și apoi spațiul de pe server se epuizează. Există instrumente pentru a remedia această situație?

Spațiul de pe server trebuie monitorizat corespunzător.

De exemplu, DBA a mers la ceai, a fost la o stațiune etc.

Când este creat un sistem de fișiere, se creează cel puțin un fel de spațiu de rezervă unde datele nu sunt scrise.

Ce se întâmplă dacă este complet sub zero?

Acolo se numește spațiu rezervat, adică poate fi eliberat și, în funcție de cât de mare a fost creat, obțineți spațiu liber. Implicit nu stiu cati sunt. Și într-un alt caz, livrați discuri astfel încât să aveți spațiu pentru a efectua o operație de reconstrucție. Puteți șterge un tabel de care sigur nu veți avea nevoie.

Există și alte instrumente?

Este întotdeauna făcută manual. Și la nivel local devine clar ce este cel mai bine de făcut acolo, pentru că unele date sunt critice, iar altele nu sunt critice. Și pentru fiecare bază de date și aplicația care funcționează cu ea, depinde de afacere. Se decide întotdeauna la nivel local.

Multumesc pentru raport! Am două întrebări. Mai întâi, ați arătat diapozitive care au arătat că atunci când tranzacțiile sunt blocate, atât dimensiunea spațiului tabel, cât și dimensiunea indexului cresc. Și mai departe pe raport au fost o grămadă de utilități care împachetează tableta. Dar indexul?

Le împachetează și ei.

Dar vidul nu afectează indexul?

Unii lucrează cu un index. De exemplu, pg_rapack, pgcompacttable. Vacuumul recreează indicii și îi afectează. Cu VACUUM FULL ideea este să suprascrieți totul, adică funcționează cu toată lumea.

Și a doua întrebare. Nu înțeleg de ce rapoartele despre replici depind atât de mult de replicarea în sine. Mi s-a părut că rapoartele sunt citite, iar replicarea este scrisă.

Ce cauzează un conflict de replicare? Avem un Maestru pe care au loc procesele. Avem un aspirator de mașină. Ce face de fapt un autovacuum? El decupează niște replici vechi. Dacă în acest moment avem o solicitare pe replica care citește aceste rânduri vechi, iar pe Master a apărut o situație în care autovacuum-ul a marcat aceste linii ca fiind posibile pentru suprascriere, atunci le-am suprascris. Și am primit un pachet de date, când trebuie să rescriem acele linii de care cererea are nevoie pe replică, procesul de replicare va aștepta expirarea pe care ați configurat-o. Și apoi PostgreSQL va decide ce este mai important pentru el. Și replicarea este mai importantă pentru el decât cererea și el va filma cererea pentru a face aceste modificări pe replică.

Andrei, am o întrebare. Aceste grafice minunate pe care le-ați arătat în timpul prezentării, sunt acestea rezultatul muncii unui fel de utilitate de-al dumneavoastră? Cum au fost realizate graficele?

Acesta este un serviciu Okmetru.

Este acesta un produs comercial?

Da. Acesta este un produs comercial.

Sursa: www.habr.com

Adauga un comentariu