Ju lutem hedhni një sy në përmbledhjen e raportit të fillimit të vitit 2016 nga Andrey Salnikov "Gabimet tipike në aplikacione që çojnë në bloat në postgresql"
Në këtë raport do të shqyrtoj gabimet kryesore në aplikacione që ndodhin gjatë fazës së projektimit dhe kodimit të aplikacionit. Do të përqendrohem vetëm në ato gabime që çojnë në bloat në Postgresql. Si rregull, këto janë fillimi i fundit të performancës së sistemit tuaj në tërësi, megjithëse në fillim nuk kishte shenja për këtë.

Më vjen mirë t'ju përshëndes të gjithëve! Ky raport nuk është kaq teknik sa ai i mëparshmi nga kolegu im. Ky raport është i orientuar kryesisht për zhvilluesit e sistemeve backend, sepse kemi një numër të konsiderueshëm klientësh. Të gjithë ata bëjnë të njëjtat gabime. Këtë do t'ju tregoj. Do t'ju shpjegoj se në çfarë mënyre këto gabime çojnë në pasojat fatale dhe negative.

Pse ndodhin gabimet? Ato ndodhin për dy arsye: në mënyrë të rastësishme, ndoshta do të kalojë dhe për shkak të mungesës së njohurive për disa mekanizma që ndodhin në nivelin midis bazës dhe aplikacionit, si dhe brenda vetë bazës.
Do t'ju tregoj tre shembuj me imazhe të tmerrshme se si u keqësua gjithçka. Në përmbledhje, do të flas mbi mekanizmin që ndodh atje. Dhe si të ballafaqohemi me ta kur ndodhin, si dhe cilat metoda parandaluese mund të përdoren për të evituar gabimet. Do të flas për mjete ndihmëse dhe do të jap lidhje të dobishme.

Kam përdorur një bazë të dhënash testuese, ku kisha dy tabela. Një tabelë me faturat e klientëve, tjetra me operacionet e këtyre faturave. Dhe me një farë periudhe herë pas here ne përditësojmë mbetjet në këto llogari.

Të dhënat fillestare të tabelës: ajo është mjaft e vogël, 2 MB. Koha e përgjigjes për bazën dhe veçanërisht për tabelën është gjithashtu shumë e mirë. Dhe një ngarkesë mjaft e mirë - 2,000 operacione në sekondë për tabelën.

Dhe nëpërmjet këtij raporti do t'ju tregoj grafikë, për të qenë e qartë se çfarë po ndodh. Do të ketë gjithmonë 2 slajde me grafikë. Slajdi i parë – është ajo që ndodh në përgjithësi në server.
Dhe në këtë situatë shohim se në të vërtetë tabela jonë është e vogël. Indeksi është i vogël në 2 MB. Kjo është grafiku i parë nga e majta.
Koha mesatare e përgjigjes në server është gjithashtu stabile, e vogël. Kjo është grafiku i sipërm të djathtas.
Grafiku i poshtëm të majtës – është transaksionet më të gjata. Shohim se transaksionet përfundohen shpejt. Dhe autovacuum këtu nuk po punon ende, sepse – ishte një test fillestar. Më pas do të punojë dhe do të jetë e dobishme për ne.

Slajdi i dytë gjithmonë do t'i kushtohet tabelës së testuar. Në këtë situatë ne vazhdimisht përditësojmë mbetjet e llogarive të klientëve. Dhe shohim se koha mesatare e përgjigjes për operacionin e përditësimit është mjaft e mirë, më pak se një milisekondë. Shohim se burimet e procesorit (kjo është grafiku i sipërm të djathtas) konsumohen gjithashtu njëlloj dhe mjaft e vogël.
Grafiku i poshtëm të djathtas tregon sa memorie operante dhe e diskut po shqyrtojmë në kërkim të rreshtit tonë të nevojshëm, para se ta përditësojmë. Dhe numri i operacioneve për tabelën – 2,000 në sekondë, ashtu siç e thashë më parë.

Dhe tani ndodhi tragjedia. Për një arsye të caktuar ndodhi një transaksion i gjatë i harruar. Arsyet zakonisht janë të zakonshme:
- Një nga më të zakonshmet – është se në kodin e aplikacionit filluam të lidheshim me një shërbim të jashtëm. Dhe ky shërbim nuk na përgjigjet. Do të thotë, hëmë një transaksion, bëmë një ndryshim në bazë dhe shkuam të lexojmë postën ose në një shërbim tjetër brenda infrastrukturës tonë, dhe për një arsye nuk na përgjigjet. Dhe kemi një sesion të ngjitur në një gjendje – nuk dihet se kur do të zgjidhet.
- Situata e dytë është kur në kod ndodhi një përjashtim. Dhe ne nuk e përpunuam përjashtimin për mbylljen e transaksionit. Dhe kemi një sesion të ngjitur me një transaksion të hapur.
- Dhe e fundit – është gjithashtu një rast mjaft i zakonshëm. Kjo është një kod i dobët. Disa kuadro hapin një transaksion. Ai mbetet i ngjitur, dhe nuk mund ta dini në aplikacion se ai është i ngjitur.
Çfarë ndodhin këto?
Kështu që fillojnë të mbushen me shpejtësi tabelat dhe indekset. Ky është efekti i bloat. Për bazën, kjo do të shfaqet në atë se koha e përgjigjes së bazës së të dhënave do të rritet ndjeshëm, dhe ngarkesa mbi serverin e bazës do të rritet. Si rezultat, aplikacioni do të vuajë. Sepse nëse në kodin tuaj shpenzuat 10 milisekonda për një kërkesë në bazë, 10 milisekonda për logjikën tuaj, atëherë funksioni juaj do ta përfundonte në 20 milisekonda. Tani situata do të jetë krejtësisht e trishtuar.
Dhe le të shohim se çfarë po ndodh. Grafiku në të majtë poshtë tregon se kemi një transaksion të gjatë. Dhe nëse shohim grafikun në të majtë lart, shohim se madhësia e tabelës nga dy megabajt është rritur papritur në 300 megabajt. Ndërkohë, sasia e të dhënave në tabelë nuk ka ndryshuar, domethënë ka një sasi të madhe mbetje.

Situata e përgjithshme për kohën mesatare të përgjigjes së serverit gjithashtu ka ndryshuar disa renditje. Domethënë, të gjitha kërkesat në server kanë filluar të varen ndjeshëm. Dhe në të njëjtën kohë, proceset e brendshme të Postgres janë aktivizuar, duke tentuar të bëjnë diçka dhe duke konsumuar burime.

Çfarë po ndodh me tabelën tonë? E njëjta gjë. Kohë mesatare e përgjigjes për tabelën ka rritur ndjeshëm. Nëse flasim konkretisht për burimet e konsumuar, shohim se ngarkesa në procesor është rritur shumë. Ky është grafiku në të djathtë lart. Ajo është rritur sepse procesori duhet të kalojë përmes shumë rreshtave të pabesueshëm për të gjetur një të vetme të nevojshme. Ky është grafiku në të djathtë poshtë. Si rezultat, numri i thirrjeve në sekondë ka filluar të ulet ndjeshëm, sepse baza nuk arrin të përpunojë të njëjtin numër kërkesash.

Na nevojitet të rikthehemi në jetë. Shkëmbejmë informacion në internet dhe kuptojmë se transaksionet e gjata çojnë në probleme. Gjejmë dhe shuajmë këtë transaksion. Dhe gjithçka kthehet në normalitet. Të gjitha funksionojnë si duhet.
Ne qetësohemi, por pas pak kohe fillojmë të vëmë re se aplikacioni nuk funksionon si para situatës emergjente. Kërkesat po përpunohen gjithashtu më ngadalë, madje shumë më ngadalë. Një herë e gjysmë deri në dy herë më ngadalë në rastin tim konkret. Ngarkesa në server gjithashtu është më e lartë se ishte para krizës.

Dhe pyetja është: "Çfarë po ndodh me bazën në atë moment?". Me bazën ndodhin situata të tilla. Në grafikun e transaksioneve shihni se ajo është ndalur dhe aty nuk ka transaksione të zgjatura. Por madhësitë e tabelës gjatë krizës janë rritur kritikisht. Dhe që nga atëherë nuk janë zvogëluar. Koha mesatare për bazën është stabilizuar. Dhe përgjigjet duket se janë të arsyeshme me një shpejtësi të pranueshme për ne. Auto-vakuumi ka filluar të jetë më aktiv dhe të bëjë diçka me tabelën, sepse i nevojitet të procesojë më shumë të dhëna.

Konkretisht për tabelën e provuar me llogaritë, ku ne ndryshojmë mbetjet: koha e përgjigjes për kërkesën duket se ka rikthyer normalitetin. Por në të vërtetë ajo është një herë e gjysmë më e lartë.
Dhe përsa i përket ngarkesës në procesor, shohim se ajo nuk është rikthyer në nivelin e nevojshëm para krizës. Dhe arsyet janë pikërisht në grafikun në të djathtë poshtë. Duke e parë, duket se ka një kalim të një sasi të caktuar të memories. Domethënë, për të gjetur rreshtin e nevojshëm, po shpenzojmë burime të serverit nga baza e të dhënave gjatë përzgjedhjes së të dhënave të panevojshme. Numri i transaksioneve në sekondë është stabilizuar.
Në përgjithësi mirë, por situata është më e keqe se ishte. Ka një degradim të dukshëm të bazës së të dhënave si pasojë e aplikacionit tonë, që punon me këtë bazë të dhënash.

Dhe për të kuptuar çfarë po ndodh, nëse nuk ishit në prezantimin e mëparshëm, tani një pak teori. Teoria mbi procesin e brendshëm. Pse është auto-vakuumi dhe çfarë bën ai?
Shumë shkurtimisht për kuptimin. Në një moment, ne kemi një tabelë. Në tabelë kemi rreshta. Këta rreshta mund të jenë aktivë, të gjallë, të nevojshëm për ne tani. Në imazh ata janë të markuar me ngjyrë të gjelbër. Dhe ka rreshta të vdekur, që janë përfunduar, janë përditësuar, kanë pasur regjistrime të reja. Dhe ata shënohen që nuk janë më të interesuar për bazën e të dhënave. Por ndodhin në tabelë për shkak të karakteristikave të Postgres.
Pse nevojitet auto-vakuumi? Në një moment, ai vjen, i drejtohet bazës së të dhënave dhe pyet: "Më jep, të lutem, id-në e transaksionit më të vjetër, që është e hapur aktualisht në bazën e të dhënave". Baza e të dhënave kthen këtë id. Dhe auto-vakuumi, duke u mbështetur në të, kalon përmes rreshtave në tabelë. Dhe kur sheh se disa rreshta janë ndryshuar nga transaksione shumë më të vjetra, ai ka të drejtë t'i shënojë ato si rreshta, të cilat mund t'i ripërdorim në të ardhmen duke regjistruar aty të dhëna të reja. Ky është një proces i prapa.
Në këtë kohë, ne vazhdojmë të punojmë me bazën e të dhënave, vazhdojmë të bëjmë disa ndryshime në tabelë. Dhe në këta rreshta, që mund t'i ripërdorim, regjistrojmë të dhëna të reja. Dhe kështu kemi një cikël, domethënë, gjithmonë kanë ndodhur disa rreshta të vdekur të vjetër, në vend të tyre regjistrojmë rreshta të rinj të nevojshëm për ne. Dhe kjo është një gjendje normale për punën e PostgreSQL.

Çfarë ndodhi gjatë krizës? Si ndodhi ky proces?
Ne kishim një tabelë në një gjendje të caktuar, disa rreshta ishin të gjallë, disa të vdekur. Erdh përheqësi automatik. Ai e pyeti bazën e të dhënave për transaksionin më të vjetër që kishim, cili ishte id e saj. Mori këtë id, e cila mund të ishte nga orë më parë, ndoshta edhe dhjetë minuta. Kjo varet nga sa ngarkesë keni në bazën e të dhënave. Dhe shkoi për të kërkuar rreshtat që mund të shënonte si të ripërdorshëm. Dhe nuk gjeti asnjë rresht të tillë në tabelën tonë.
Por ne vazhdojmë të punojmë me tabelën. Bëjmë diçka në të, përditësojmë, ndryshojmë të dhënat. Dhe çfarë duhet të bëjë baza e të dhënave në këtë kohë? Ajo nuk i mbetet asgjë tjetër veçse të shkruajë rreshta të rinj në fund të tabelës ekzistuese. Kështu që fillon të rritet madhësia e tabelës.
Realistshëm, për punën tonë na duhen rreshtat e gjelbër. Por gjatë një problemi të tillë, ne përfundojmë me një përqindje shumë të ulët të rreshtave të gjelbër në gjithë vëllimin e tabelës.
Dhe kur ne kryejmë një kërkesë, baza e të dhënave detyrohet të kalojë nëpër të gjitha rreshtat: edhe të kuqit, edhe të gjelbërit, për të gjetur rreshtin e duhur. Efekti i rritjes së tabelës me të dhëna të padobishme quhet "bloat", i cili gjithashtu hëngër hapësirën tonë në disk. E mbani mend, ishim 2 MB, u bë 300 MB? Tani zëvendësoni megabajtët me gigabajtët dhe ashtu do të humbni shpejt të gjitha burimet e diskut tuaj.

Cilat mund të jenë pasojat për ne?
- Në shembullin tim, tabela dhe indeksi u rritën 150 herë. Disa nga klientët tanë kanë pasur raste më fatale, kur thjesht hapësira në disk filloi të mbaronte.
- Madhësia e tabelave nuk do të zvogëlohet ndonjëherë vetë. Përheqësi automatik në disa raste mund të presë bishtin e tabelës, nëse aty ka vetëm rreshta të vdekur. Por pasi ndodhin rotacione të vazhdueshme, një rresht i gjelbër mund të ngecet në fund dhe të mos përditësohet, ndërsa të tjerët do të shkruhen diku në fillim të tabelës. Por kjo është një ngjarje aq e pamundur, saqë tabela juaj të zvogëlohet natyrshëm, prandaj nuk duhen pasur shpresa për këtë.
- Baza e të dhënave duhet të kalojë nëpër të gjithë radhët e padobishme. Dhe ne shpenzojmë burime diskun, shpenzojmë burime të procesorit dhe energjinë elektrike.
- Dhe kjo ndikon drejtpërdrejt në aplikacionin tonë, sepse në fillim shpenzonim 10 milisekonda për kërkesën, 10 milisekonda për kodin tonë, ndërsa gjatë krizës filluam të shpenzojmë një sekondë për kërkesën dhe 10 milisekonda për kodin, dmth. performanca e aplikacionit ra ndjeshëm. Dhe kur zvogëluam krizën, na duhej 20 milisekonda për kërkesën, 10 milisekonda për kodin. Kjo do të thotë se ne fatkeqësisht humbëm 1.5 herë për performancën. Dhe kjo është për shkak të një transaksioni që ngeci, ndoshta, për fajin tonë.
- Dhe pyetja është: "Si ta kthejmë gjithçka prapa?" që të kemi gjithçka mirë dhe kërkesat të funksionojnë po aq shpejt sa para krizës.

Për këtë ka një cikël të caktuar punësh që kryhen.
Së pari, na nevojitet të gjejmë tabelat problematike që janë rritur. Ne kuptojmë se për disa tabela, shkrimi po ndodh më aktivisht, për disa më pak aktivisht. Dhe për këtë përdoret zgjerimi . Duke instaluar këtë zgjerim, mund të shkruani kërkesa që ju ndihmojnë të gjeni tabelat që janë rritur mjaft.
Pasi të keni gjetur këto tabela, ato duhet të kompresohen. Për këtë ka tashmë mjete. Në kompaninë tonë ne përdorim tre mjete. E para - VACUUM FULL i integruar. Ai është i ashpër, i ulët dhe i pamëshirshëm, por ndonjëherë është shumë i dobishëm. dhe – janë mjete të palëve të treta për kompresimin e tabelave. Dhe ato janë më të kujdesshme ndaj bazës së të dhënave.
Ato përdoren në varësi të asaj se çfarë ju është më e përshtatshme. Por për këtë do të flas në fund. E rëndësishme është që ka tre mjete. Ka për të zgjedhur.
Pasi të kemi rregulluar gjithçka dhe siguruar që gjithçka është mirë, duhet të dimë si ta parandalojmë këtë situatë në të ardhmen:
- Parandalimi është mjaft i thjeshtë. Duhet të ndjekim gjatësi e seancave në serverin Master. Veçanërisht seancat e rrezikshme që janë në gjendje idle in transaction. Ato janë ato që hapën një transaksion, bënë diçka dhe u larguan ose thjesht ngelën, humbën në kod.
- Dhe për ju, si zhvillues, është e rëndësishme të testoni kodin në momentin e shfaqjes së këtyre situatave. Nuk është e vështirë të bëhet. Kjo do të ishte një kontroll i dobishëm. Do t'ju ndihmojë të evitoni shumë "probleme fëmijësh" që lidhen me transaksionet e gjata.

Në këto grafikë doja t'ju tregoj se si u ndryshua tabela dhe sjellja e bazës së të dhënave pas kryerjes së VACUUM FULL në tabelë. Kjo nuk është në prodhim.
Madhësia e tabelës u rikthye menjëherë në gjendjen normale të punës në disa megabajt. Kjo nuk e nd impacton ndjeshëm kohën mesatare të përgjigjes nga serveri.

Por konkretisht për tabelën tonë të testimit, ku kemi azhurnuar mbetjet në llogari, ne shohim se koha mesatare e përgjigjes për kërkesën e azhurnimit të të dhënave në tabelë ka rënë në nivelin para aksidentit. Burimet e konsumuar nga procesori për ekzekutimin e kësaj kërkese gjithashtu ranë në nivelin para aksidentit. Dhe grafiku në fund të djathtë tregon se tani ne jemi duke gjetur pikërisht rreshtin që na nevojitet menjëherë, pa kaluar përmes një grumbulli rreshtash të vdekur që ishin para kompresimit të tabelës. Koha mesatare e kërkesave mbeti në nivelin e njëjtë. Por këtu kam, më shumë, një gabim të harduerit tim.

Kjo është historia e parë. Ajo është më e zakonshmja. Dhe ndodh me të gjithë, pavarësisht nga përvoja e klientit, sa të kualifikuar janë programuesit atje. Herët a vonë, kjo ndodh.
Historia e dytë, në të cilën ne shpërndajmë ngarkesën dhe optimizojmë burimet serverike.

- Kemi kaluar tashmë dhe jemi bërë djem seriozë. Dhe e kuptojmë se kemi një replikë dhe do të ishte mirë të balancojmë ngarkesën: të shkruajmë në Master dhe të lexojmë nga replika. Zakonisht, kjo situatë ndodh kur duam të përgatisim ndonjë raport ose ETL. Dhe biznesi është shumë i lumtur për këtë. Ai dëshiron shumë raporte me një mori analitikash të komplikuara.
- Raportet janë shumë-orëshe, sepse analitika e komplikuar nuk mund të llogaritet brenda disa milisekondash. Ne, si djem të guximshëm, shkruajmë kod. Bëjmë në aplikacionin e injektuar që regjistrimi po bëhet në Master, raportet ekzekutohen në replikë.
- Ne shpërndajmë ngarkesën.
- Gjithçka funksionon shkëlqyeshëm. Ne jemi të mrekullueshëm.

Dhe si duket kjo situatë? Konkraktisht në këto grafika, unë kam shtuar kohën e transaksioneve nga replika për kohëzgjatjen e transaksioneve. Të gjitha grafikat e tjera lidhen vetëm me serverin Master.
Tabela me raportet në këtë pikë ka rritur. Ata janë bërë më shumë. Ne shohim se koha mesatare e përgjigjes së serverit është stabile. Ne shohim se në replikë kemi një transaksion të gjatë, i cili po punon për 2 orë. Shohim punën e qetë të autovakuumit, i cili po përpunon rreshtat e vdekur. Dhe gjithçka është në rregull.

Konkretisht për tabelën që po testojmë, ne po vazhdojmë të azhurnojmë mbetjet në llogari. Dhe gjithashtu kemi kohë të qëndrueshme përgjigjeje për kërkesën, konsum të qëndrueshëm burimesh. Gjithçka është në rregull.

Tjetër është se gjithçka është në rregull deri në momentin kur këto raporte fillojnë të përplasen për shkak të konflikteve me replikimin. Dhe ato përplasen me një periudhë të vazhdueshme.
Ne po shohim në internet dhe po fillojmë të lexojmë përse ndodh kjo. Dhe gjejmë një zgjidhje.
Zgjidhja e parë - të rrisim vonesën e replikimit. Ne e dimë se raporti ynë punon për 3 orë. Vendosim vonesën e replikimit - 3 orë. Aktivizojmë gjithçka, por akoma kemi probleme që raportet nganjëherë përplasen.
Duam që gjithçka të jetë perfekte. Po kërkojmë më tej. Dhe gjejmë një konfigurim fantastik në internet - hot_standby_feedback. E aktivizojmë. Hot_standby_feedback na lejon të mbajmë punën e autovakuumit në Master. Kështu ne i shmangim përfundimisht konfliktet e replikimit. Dhe gjithçka punon mirë me raportet.

Çfarë ndodh me Master-serverin në këtë kohë? Po në Master-serverin ndodhet një krizë totale. Tani ne e shohim grafikun kur aktivizova të dy këto konfigurime. Dhe shohim që sesioni në replikë, dikur, ndikon në situatën në Master-server. Ajo vërtet ndikon, sepse e ka ndaluar autovakuumin, i cili pastron rreshtat e vdekur. Madhësia e tabelës sërish është rritur. Koha mesatare e ekzekutimit të kërkesave në të gjithë bazën e të dhënave gjithashtu është rritur. Autovakuimet janë pak të ngarkuara.

Konkretisht për tabelën tonë, ne shohim se azhurnimi i të dhënave po rritet sërish. Konsumi i burimeve të procesorit gjithashtu është rritur shumë. Ne po kalojmë sërish një sasi të madhe të rreshtave të vdekur e të padobishëm. Dhe koha e përgjigjes për këtë tabelë, numri i transaksioneve ka rënë.

Si do të duket kjo, nëse nuk e dimë për çfarë kam folur më parë?
- Ne fillojmë të kërkojmë probleme. Nëse kemi hasur të këqijat në pjesën e parë, ne e dimë se mund të jetë arsyeja në një transaksion të gjatë dhe shkojmë te Master. Problemi ndodhet në Master. Ai është duke u përshpejtuar. Ai ngrohet, Load Average është nën njëqind.
- Kërkesat ngadalësohen atje, por nuk shohim ndonjë transaksion të gjatë. Dhe nuk kuptojmë se çfarë ndodh. Nuk e dimë se ku të kërkojmë.
- Kontrollojmë pajisjet serverike. Mund të kemi dëmtuar raid-in. Mund të jetë se na është djegur një modul memorje. Mund të ndodhin shumë gjëra. Por jo, serverët janë të rinj, gjithçka funksionon shkëlqyeshëm.
- Të gjithë po vrapojnë: administratorët, zhvilluesit dhe drejtori. S'gjen ndihmë.
- Dhe në një moment, gjithçka papritur fillon të rregullohet vetë.

Në replikë, njëherësh, kërkesa u përpunua dhe kaloi. Ne morëm raportin. Biznesi është akoma i kënaqur. Siç e shohim, tabela jonë është rritur përsëri dhe nuk ka në plan të zvogëlohet. Në grafikun e sesioneve kam lënë një copë nga kjo transaksion e gjatë nga replikimi, në mënyrë që të mund të vlerësoni sa kohë kalon derisa situata të stabilizohet.
Sesioni u largua. Dhe vetëm pas një kohe, serveri fillon të arrijë një farë rendi. Dhe koha mesatare e përgjigjeve për kërkesat në serverin Master kthehet në normë. Sepse, përfundimisht, avakuumi automatik mori mundësinë të pastronte dhe të shënonte këto rreshta të vdekur. Dhe ai filloi të bëjë punën e tij. Dhe sa më shpejt ta bëjë, aq më shpejt do të arrijmë në rend.

Në tabelën e testuar, ku ne përditësojmë saldo, shohim të njëjtën pamje. Koha mesatare e përditësimit gjithashtu normalizohet gradualisht. Burimet e konsumuar nga procesori gjithashtu pakësohen. Dhe numri i transaksioneve për sekondë kthehet në normë. Por përsëri, norma nuk është ajo që kishim para katastrofës.

Në çdo rast, po marrim një rënie të performances si në rastin e parë, ndoshta 1.5-2 herë, ndonjëherë edhe më shumë.
Duket se bëjmë gjithçka siç duhet. E shpërndajmë ngarkesën. Pajisjet nuk janë të papërdorura. Kemi ndarë kërkesat siç duhet, por prapë gjërat nuk funksionojnë ashtu siç duhet.
- Të mos aktivizoni hot_standby_feedback? Po, nuk rekomandohet ta aktivizoni pa ndonjë arsye të fortë. Sepse ky rregullim ndikon drejtpërdrejt në serverin Master dhe pezullon punën e avakumit automatik atje. Nëse e aktivizoni në ndonjë replikë dhe harroni për këtë, mund të vrisni serverin Master dhe të keni probleme serioze me aplikacionin.
- Të rrisni max_standby_streaming_delay? Po, për raportet – kjo ashtu është. Nëse keni një raport tre orësh dhe nuk doni që të dështojë për shkak të konflikteve të replikimeve, thjesht rrisni vonesën. Një raport i gjatë kurrë nuk kërkon të dhëna që sapo erdhën në bazë. Nëse është një raport tre orësh, do të thotë se e startoni për një periudhë të vjetër të të dhënave. Dhe ju, çfarëdo që të jetë vonesa tre orëshe ose gjashtë orëshe – nuk ka asnjë rëndësi, por kështu do të merrni raportet me stabilitet dhe nuk do të keni probleme me dështimin e tyre.
- Natyrisht, duhet të kontrolloni sesionet e gjata në replikat, veçanërisht nëse vendosët të aktivizoni hot_standby_feedback në replikë. Sepse mund të ndodhin shumë gjëra. I dhamë atë replikë zhvilluesit që të testonte kërkesat. Ai shkroi një kërkesë të çmendur. E nisi dhe u largua për të pirë çaj, ndërsa ne morëm një Master të mbingarkuar. Apo mund të kemi lejuar një aplikacion të gabuar atje. Situatat janë të ndryshme. Sesionet në replikat duhet të kontrollohen aq të kujdesshëm sa dhe ato në Master.
- Dhe nëse keni kërkesa të shpejta dhe të gjata në replikat, atëherë në këtë rast është më mirë t'i shpërndani ato. Kjo është lidhja për streaming_delay. Për të shpejtat të keni një replikë me një vonesë të vogël replikimi. Për kërkesat e gjata raportuese të keni një replikë që mund të vonohet për 6 orë ose një ditë. Kjo është një situatë krejt normale.
Të heqim pasojat gjithmonë me të njëjtin mënyrë:
- Gjejmë tabelat e fryra.
- Dhe i kompresojmë me mjetin më të përshtatshëm që kemi.
Historia e dytë përfundoi këtu. Kalohet te historia e tretë.

Po ashtu, mjaft e zakonshme për ne, në të cilën bëjmë migrim.

- Çdo produkt softuerik rritet. Kërkesat për të ndryshojnë. Ne gjithmonë duam të zhvillohemi. Dhe ndonjëherë ndodh që na nevojitet të përditësojmë të dhënat në tabelë, pra të bëjmë një përditësim për migrimin tonë në funksionalitetin e ri që po implementojmë si pjesë e zhvillimit tonë.
- Formati i vjetër i të dhënave nuk e përmbush. Supozoni se tani do të drejtohemi te tabela e dytë, ku kam operacionet për këto llogari. Dhe, le të themi, që ato ishin në rubla, dhe vendosëm të rritim saktësinë dhe të bëjmë në cope. Dhe për këtë na nevojitet të bëjmë një përditësim: fusha me shumën e operacionit të shumëzohet me njëqind.
- Në botën moderne ne përdorim mjete automatizimi për kontrollin e versioneve të bazës së të dhënave. Supozoni, . E shkruajmë migrimin tonë atje. E testojmë në bazën tonë të testimit. Gjithçka shkon mirë. Përditësimi kalon. Ndalesa e punës për një kohë të caktuar, por përndryshe marrim të dhëna të përditësuara. Dhe mund të fillojmë funksionalitetin e ri me këtë. Të gjithë e kemi provuar, kontrolluar. Të gjithë e konfirmuan.
- Kemi kryer punime planifikuara, kemi bërë migrimin.

Ja, migrimi me përditësimin është para jush. Duke qenë se këto janë operacione mbi llogaritë, tabela kishte 15 GB. Dhe pasi që ne po përditësojmë çdo rresht, ne e rritëm tabelën me dy herë për shkak se riparësojmë çdo rresht.

Gjatë migrimit, ne nuk mund të bënim asgjë me këtë tabelë, sepse të gjitha kërkesat për të ishin në pritje dhe prisnin që ky përditësim të përfundonte. Por dua të tërheq vëmendjen tuaj ndaj shifrave që janë në boshtin vertikal. Pra, mesatarja e kohës së kërkesës para migrimit ishte rreth 5 milisekonda dhe ngarkesa mbi procesor, numri i operacioneve blokues për leximin e memories të diskut ishte më pak se 7.5.

Kemi kryer migrimin dhe përsëri morëm probleme.
Migrimi kaloi me sukses, por:
- Funksionaliteti i vjetër filloi të realizohet më ngadalë.
- Tabela përsëri u rrit në madhësi.
- Ngarkesa në server përsëri u rrit më shumë se ç'ishte.
- Dhe, sigurisht, ne ende merremi me funksionalitetin që punonte mirë, e kemi përmirësuar pak.
Dhe kjo përsëri është bloat, që na shqetëson përsëri.

Këtu po demonstroj që tabela, ashtu si në dy rastet e mëparshme, nuk po planifikon të kthehet në madhësitë e mëparshme. Ngarkesa mesatare mbi server duket e arsyeshme.

Dhe nëse i drejtohemi tabelës me llogaritë, do të shohim se mesatarja e kohës së kërkesës për këtë tabelë ka dyfishuar. Ngarkesa mbi procesor dhe numri i rreshtave të lexuar në memory ka shkuar mbi 7.5, kur ishte nën këtë nivel. Dhe ngarkesa për procesorët është dyfishuar, ndërsa për operacionet blokues është rritur 1.5 herë, pra kemi marrë degradim të performancës së serverit. Dhe si pasojë – degradim të performancës së aplikacionit tonë. Ndërkohë, numri i thirrjeve ka mbetur në nivele të ngjashme.

Dhe këtu është e rëndësishme të kuptohet se si të bëhen këto migrime siç duhet. Dhe ato janë të nevojshme. Ne shpesh bëjmë këto migrime.
- Migrime të tilla të mëdha nuk bëhen automatikisht. Ato gjithmonë duhet të jenë nën kontroll.
- Kontrolli është i nevojshëm nga një person i njohur. Nëse keni një DBA në ekipin tuaj, le t'ia besoni DBA-së këtë. Kjo është puna e tij. Nëse jo, personi më i përvojë le të bëjë këtë, ai që di si të punojë me bazat e të dhënave.
- Skema e re e databazës, edhe nëse ne përditësojmë vetëm një kolonë, gjithmonë e përgatitim me hapa, që do të thotë para se të lëshojmë versionin e ri të aplikacionit:
- Shtohet fusha të reja, në të cilat do të shkruhen të dhënat e përditësuara.
- Shkarkojmë të dhënat nga fusha e vjetër në fushën e re në pjesë të vogla. Pse e bëjmë këtë? Së pari, ne gjithmonë kontrollojmë procesin e këtij transferimi. Ne e dimë se sa shumë batch-e kemi bërë dhe sa na kanë mbetur.
- Dhe efekti pozitiv i dytë është se midis çdo batch-i të tillë, mbyllim transaksionin, hapim një të re dhe kjo lejon avto-vakumin të funksionojë mbi tabelë, duke shënuar rreshtat e vdekur për ri-shfrytëzim.
- Për rreshtat që do të shfaqen gjatë funksionimit të aplikacionit (ne kemi akoma aplikacionin e vjetër në punë) shtojmë një trigger që shkruan vlerat e reja në fushat e reja. Në rastin tonë – është një shumëzim me njëqind të vlerës së vjetër.
- Nëse jemi shumë të vendosur dhe duam të përdorim të njëjtën fushë, atëherë pas përfundimit të të gjitha migrimeve dhe para lëshimit të versionit të ri të aplikacionit, ne thjesht ribemë emrat e fushave. Të vjetrat në një emër të sajuar, dhe fushat e reja ribemë emrat në të vjetrat.
- Dhe vetëm pasi ta bëjmë këtë, e lancojmë versionin e ri të aplikacionit.
Dhe në këtë mënyrë ne nuk do të kemi bloat dhe nuk do të kemi degradim të performancës.
Kjo përfundoi historinë e tretë.

Tani pak më në detaje për mjetet që përmenda në historinë time të parë.
Para se të kërkoni bloat, është e domosdoshme të instaloni zgjerimin .
Për të mos zbuluar kërkesa, ne në punën tonë i kemi shkruar këto kërkesa. Ju mund t’i përdorni ato. Këtu janë paraqitur dy kërkesa.
- E para punon për një kohë të gjatë, por gjithsesi ajo do t'ju tregojë vlerat e sakta të bloat për tabelën.
- E dyta punon më shpejt dhe është shumë efektive kur duhet të vlerësosh shpejt – a ka bloat apo jo për tabelën. Dhe gjithashtu duhet të kuptoni se bloat në një tabelë PostgreSQL është gjithmonë e pranishme. Kjo është karakteristika e modelit të tij MVCC.
- Dhe 20% bloat është normale për tabelat në shumicën e rasteve. Pra, nuk duhet të shqetësoheni dhe të kompresoni këtë tabelë.
Si të identifikojmë tabelat që janë zgjeruar, ne e shqyrtuam, sidomos kur ato janë zgjeruar me të dhëna të padobishme.
Tani për atë se si të korrigjojmë bloat:
- Nëse kemi një tabelë të vogël dhe disqe të mira, pra në tabelë deri në një gigabajt është plotësisht e mundur të përdorim VACUUM FULL. Ai do të marrë një bllokim ekskluziv për tabelën për disa sekonda dhe mjaftueshëm, përveç kësaj, ai bën gjithçka shpejt dhe me forcë. Çfarë bën VACUUM FULL? Ai merr një bllokim ekskluziv për tabelën dhe nga tabelat e vjetra shkruan rreshtat aktivë në një tabelë të re. Dhe në fund i ndërron vendet. Fajlet e vjetra i fshin, dhe zëvendësimet e reja i vendos në vend të këtyre. Por gjatë punës së tij ai merr një bllokim ekskluziv për tabelën. Kjo do të thotë që ju nuk mund të bëni asgjë me këtë tabelë: as të shkruani në të, as të lexoni nga ajo, as ta modifikoni. Dhe VACUUM FULL kërkon hapësirë shtesë në disk për të shkruar të dhënat.
- Mjeti tjetër . Nga parimi i tij është shumë i ngjashëm me VACUUM FULL, sepse gjithashtu shkruan të dhënat nga skedarët e vjetër në të rinjtë dhe i ndërron ato në tabelë. Por në këtë rast, ai nuk merr një bllokim ekskluziv për tabelën në fillim, por e merr vetëm në momentin kur ka të dhëna të gatshme për të zëvendësuar skedarët. Kërkesat për burimet e diskut janë të ngjashme me ato të VACUUM FULL. Ju nevojitet hapësirë e shtuar në disk, dhe kjo ndonjëherë është kritike nëse keni tabela terabajtëshe. Ai gjithashtu është mjaft kërkues në procesor, sepse kryen punë aktive me hyrje-dalje.
- Mjeti i tretë është . Ai është më i kujdesshëm ndaj burimeve, sepse punon pak ndryshe. Thelbi i pgcompacttable është se me azhurnimet në tabelë, ai i zhvendos të gjithë rreshtat aktivë në fillim të tabelës. Dhe më pas ekzekuton një vakuum mbi këtë tabelë, sepse ne e dimë se në fillim kemi të gjallë, dhe në fund të vdekur. Dhe vakuumi vetë ndalon këtë bisht, pra nuk kërkon shumë hapësirë të shtuar në disk. Dhe gjithashtu mund të optimizohet për burimet.
Këtu përfundon diskutimi për mjetet.

Nëse tema e bloat-i ju intereson dhe dëshironi të hulumtoni më tej, ja disa lidhje të dobishme:
- – është një referat i kolegut tim. Ai është i përgjithshëm mbi atë se ku shkon hapësira në Postgres gjatë punës dhe jetës së tij. Dhe ka një pjesë të madhe dhe shumë të detajuar teknike për administratorët e bazave të dhënash në lidhje me bloat-in.
- – është një lidhje në repozitorin tonë, ku ruajmë shumë skripte të dobishme për kontrollet e gjendjes së bazës së të dhënave. Aty mund të gjeni skripte për të kërkuar bloat.
- dhe lidhje për mjetet që do t'ju ndihmojnë të optimizoni tabelat.
- – është një postim i kolegut tim. Aty ai analizon në mënyrë të detajuar bloat-in në një nivel më të afërt me administratorët.
Këtë herë kam përpiquar të paraqes një paralajmërim për zhvilluesit, sepse ata janë klientët tanë të drejtpërdrejtë të bazave të të dhënave dhe duhet të kuptojnë se cilat veprime sjellin pasojat. Shpresoj të kem arritur ta bëj këtë. Faleminderit për vëmendjen!
Pyetje
Faleminderit për referatin! Ju folët për mënyrat se si mund të identifikohen problemet. Si mund t’i parandalojmë ato? Pra, unë kam pasur një situatë kur kërkesat ishin të ngjitura jo vetëm për shkak se ato lidhen me disa shërbime të jashtme. Ishin disa lidhje të çuditshme. Kishin disa kërkesa të vogla, të padëmshme, që kishin ngecur për një ditë, e më pas fillonin të bënte çmenduri. Pra, duket shumë si ajo që po përshkruani. Si mund ta monitoroj këtë? Të rri e të shikoj vazhdimisht se cila kërkesë është ngjitur? Si mund ta parandaloj këtë?
Në këtë rast, kjo është një detyrë për administratorët e kompanisë suaj, nuk është domosdoshmërisht për DBA.
Unë jam administrator.
Në PostgreSQL ekziston një pamje e tillë, si pg_stat_activity, ku shfaqen kërkesat që janë të ngjitura. Dhe ju mund të shihni se sa gjatë ka ngecur.
A duhet të hyj çdo 5 minuta dhe të shikoj?
Konfiguroni cron dhe kontrolloni. Nëse keni një kërkesë të gjatë, dërgoni një email dhe mjafton. Do të thotë, nuk është e nevojshme të shikoni me sy, kjo mund të automatizohet. Do t'ju vijë një email dhe ju reagoni për të. Ose mund ta ndalini automatikisht.
A ka arsye të dukshme përse ndodhin këto?
Unë disa i kam përmendur. Të tjerat janë shembuj më të komplikuar. Dhe aty do të ishte një bisedë e gjatë.
Faleminderit për referatin! Desha të pyes për mjetin pg_repack. Nëse ai nuk bën bllokim ekskluziv, atëherë...
Ai bën bllokim ekskluziv.
… atëherë unë potencialisht mund të humbas të dhëna. A duhet aplikacioni im të mos shkruajë në këtë kohë?
Jo, ai punon normalisht me tabelën, pra pg_repack së pari transferon të gjitha rreshtat aktivë që ka. Natyrisht, disa shkrime ndodhin në tabelë. Ai thjesht e shton atë bishtin.
Pra, në fund ai e bën atë?
Në fund, ai merr një bllokim ekskluziv për të ndërruar vendet e këtyre skedarëve.
A do të jetë më shpejt se VACUUM FULL?
VACUUM FULL, si fillon, menjëherë merr bllokimin ekskluziv. Dhe derisa të mos bëjë gjithçka, ai nuk do ta lërë atë. Ndërsa pg_repack merr bllokimin ekskluziv vetëm në momentin e zëvendësimit të skedarëve. Në atë moment nuk mund të shkruani, por të dhënat nuk do të humbasin, çdo gjë do të jetë në rregull.
Përshëndetje! Keni folur rreth punës së avtokompresionit. Kishte një grafik me kuti të kuqe, të verdha dhe të gjelbra. Domethënë, të verdhat - ai i shënon si të fshirë. Dhe si rrjedhojë, në to mund të shkruani diçka të re?
Po. Postgres nuk i fshin rreshtat. Ai ka një specifikë të tillë. Nëse ne përditësojmë një rresht, e shënojmë atë të vjetër si të fshirë. Atje vendoset ID e transaksionit që e ndryshoi këtë rresht dhe shkruajmë një rresht të ri. Dhe kemi seanca që potencialisht mund t'i lexojnë ato. Në një moment ata bëhen krejtësisht të vjetëruar. Dhe esenca e funksionimit të avtokompresionit është që ai kalon përmes këtyre rreshtave dhe i shënon ato si të panevojshme. Dhe aty mund të ripërshtaten të dhënat.
E kuptova. Por pyetja është disi ndryshe. Nuk e përfundova. Supozoni që kemi një tabelë. Në të ka fusha me madhësi të ndryshueshme. Dhe nëse përpiqem të fus diçka të re, atëherë mund të mos hyjë thjesht në një qelb të vjetër.
Jo, aty gjithsesi të gjithë rreshti përditësohet. Në Postgres ka dy modele të ruajtjes së të dhënave. Ai zgjidh sipas llojit të të dhënave. Ka të dhëna që ruhen drejtpërdrejt në tabelë, dhe gjithashtu ka të dhëna tos. Këto janë sasi të mëdha të dhënash: tekst, json. Ato ruhen në tabela të veçanta. Dhe për këto tabela ndodh e njëjta histori me bloat, dmth gjithçka është e njëjtë. Thjesht janë të ndara.
Faleminderit për raportin! Sa e pranueshme është të përdorim kërkesa statement timeout për të kufizuar kohëzgjatjen?
Shumë e pranueshme. Ne e përdorim kudo. Dhe duke qenë se nëna tonë nuk kemi shërbime, ofrojmë mbështetje të largët, ka klientë mjaft të ndryshëm. Dhe të gjithë janë mjaft të kënaqur me këtë. Domethënë, kemi detyra në cron që kontrollojnë. Thjesht diskutohet me klientin koha e seancave, përpara së cilës ne nuk ndërpremë. Kjo mund të jetë një minutë, mund të jetë 10 minuta. Kjo varet nga ngarkesa në bazë dhe objektivi i saj. Por për të gjithë ne përdorim pg_stat_activity.
Faleminderit për raportin! Po përpiqem ta përshtas raportin tuaj në aplikacionet e mia. Dhe duket se ne gjithandej fillojmë transaksionin, çdo herë e përfundojmë atë në mënyrë të qartë. Nëse ndonjë përjashtim ndodh, megjithatë ndodh rollback. Dhe këtu e mendova. A mund të fillojë një transaksion në mënyrë të paqartë? Kjo është një sugjerim për vajzën, ndoshta. Nëse thjesht bëj një përditësim të rreshtit, transaksioni do të fillojë në PostgreSQL dhe do të përfundojë vetëm kur të ndodhi çarja e lidhjes?
Nëse tani flisni për nivelin e aplikacionit, atëherë kjo varet nga ai drejtues që po përdorni, nga ai ORM që përdoret. Atje ka shumë cilësime. Nëse keni aktivizuar auto commit on, atëherë fillon një transaksion, menjëherë mbyllet.
Domethënë, ajo mbyllet menjëherë pas përditësimit?
Kjo varet nga cilësimet. Një cilësim e përmenda. Ky është auto commit on. Ai është mjaft i zakonshëm. Nëse është aktivizuar, atëherë një transaksion fillohet dhe mbyllet menjëherë. Nëse nuk e keni thënë qartë "fillo transaksionin" dhe "përfundo transaksionin", por thjesht e keni nisur një pyetje në sesion.
Përshëndetje! Faleminderit për raportin! Të supozojmë se kemi një bazë që po rritet dhe papritur në serveri po i mbaron vendi. A ka ndonjë mjet për të korrigjuar këtë situatë?
Vendin në server duhet të monitorohet në të vërtetë.
Për shembull, DBA shkoi të pinte çaj, ishte në pushim etj.
Kur krijohet sistemi i skedarëve, ka të paktën një hapësirë rezervë, ku nuk shkruhen të dhëna.
Dhe nëse është krejtësisht në zero?
Atje quhet hapësirë e rezervuar, dmth ajo mund të çlirohet dhe në varësi të asaj se sa e madhe është krijuar, ju keni marrë hapësirë të lirë. Nuk e di sa është për parazgjedhje atje. Në një rast tjetër – duhen sjellë disqe, në mënyrë që të keni hapësirë për të realizuar operacionin e rikthimit. Mund të fshini ndonjë tabelë që ju garanton që nuk ju nevojitet.
Nuk ka mjete të tjera?
Kjo është gjithmonë punë manuale. Dhe në bazë të vendit, identifikohet se çfarë është më e mira të bëhet, sepse ka të dhëna kritike, ka të dhëna jo kritike. Dhe për çdo bazë dhe aplikacion që punon me të, kjo varet nga biznesi. Gjithmonë zgjidhet sipas hapësirës.
Faleminderit për raportin! Kam dy pyetje. E para, ju treguat diapozitivë ku tregonit se në rastin e transaksioneve të ngecura rritet si vëllimi i hapësirës tabelore, ashtu edhe madhësia e indeksit. Dhe më pas në raport ishte një sërë utilitarësh që paketojnë tabelën. Por çfarë ndodh me indeksin?
Ata gjithashtu i paketojnë.
Por vakuumi nuk preket indeksin?
Disa punojnë me indekset. Për shembull, pg_rapack, pgcompacttable. Vakumi krijon përsëri indekset, e ndikon ato. Qëllimi i VACUUM FULL është që të ridëshmojë gjithçka, domethënë punon me të gjithë.
Dhe pyetja e dytë. Nuk e kuptova pse raportet në replikat varen kaq shumë nga vetë replikimi. Më dukej se raportet janë lexime, ndërsa replikimi është shkrim.
Ku ndodh konflikti i replikimit? Ne kemi një Master, ku ndodhin proceset. Ndodh një avtokombinim. Avtokombinimi, në fakt, çfarë bën? Ai eliminon disa rreshta të vjetër. Nëse në këtë kohë në replikë ka një kërkesë që lexon këta rreshta të vjetër, dhe në Master ka ndodhur situata që avtokombinimi i ka shënuar këta rreshta si të mundshëm për rikonstruktim, ne i kemi rikonstruktuar. Dhe na është dërguar një paketë të dhënash, kur duhet të rikonstruktojmë ata rreshta që janë të nevojshëm për kërkesën në replikë, procesi i replikimit do të presë atë kohë të skadimit që keni vendosur. Pastaj PostgreSQL do të vendosë se çfarë është më e rëndësishme për të. Dhe replikimi është më i rëndësishëm për të se sa kërkesa dhe ai do të ndalojë kërkesën për të realizuar këto ndryshime në replikë.
Andrej, kam një pyetje. Këto grafikët e mrekullueshëm që treguat gjatë prezantimit, janë rezultati i punës së ndonjë utiliti tuaj? Çfarë përdoret për të ndërtuar grafikët?
Ky është një shërbim .
A është ky një produkt komercial?
Po. Ky është një produkt komercial.
Burimi: habr.com
