Jag föreslÄr att ni bekantar er med avrapporteringen frÄn början av 2016 av Andrej Salnikov "Typiska fel i applikationer som leder till bloat i PostgreSQL"
I den hÀr rapporten kommer jag att gÄ igenom de vanligaste felen i applikationer som uppstÄr under design- och kodningsfasen av applikationen. Jag kommer endast att ta upp de fel som leder till bloat i PostgreSQL. Vanligtvis Àr detta början pÄ slutet för systemets prestanda som helhet, Àven om det frÄn början inte fanns nÄgra tecken pÄ detta.

Jag hÀlsar er alla vÀlkomna! Denna förelÀsning Àr inte lika teknisk som den föregÄende frÄn min kollega. Den hÀr förelÀsningen riktar sig frÀmst till utvecklare av backend-system, eftersom vi har ett ganska stort antal kunder. Och alla gör samma misstag. Det Àr om dessa jag kommer att berÀtta. Jag kommer att förklara vilka katastrofala och negativa konsekvenser dessa fel kan leda till.

Varför uppstÄr felen? De uppstÄr av tvÄ anledningar: antingen genom tur, att det kanske fungerar, eller av okunskap om vissa mekanismer som hÀnder pÄ nivÄn mellan databasen och applikationen, samt i sjÀlva databasen.
Jag kommer att ge er tre exempel med hemska bilder av hur allt blev dÄligt. Jag kommer kort att beskriva de mekanismer som förekommer dÀr. Och hur man kan hantera dem nÀr de intrÀffar, samt vilka förebyggande metoder som kan anvÀndas för att undvika fel. Jag kommer att berÀtta om hjÀlpprogram och ge anvÀndbara lÀnkar.

Jag anvÀnde en testdatabas dÀr jag hade tvÄ tabeller. En tabell för kundkonton och den andra för transaktioner pÄ dessa konton. Med viss periodicitet uppdaterar vi saldona pÄ dessa konton.

Ursprungliga data för tabellen: den Ă€r ganska liten, 2 MB. Svarstiden för databasen och specifikt för tabellen Ă€r ocksĂ„ mycket bra. Och en ganska bra belastning â 2 000 operationer per sekund pĂ„ tabellen.

Och genom denna förelÀsning kommer jag att visa er grafer sÄ att det tydligt ska framgÄ vad som hÀnder. Det kommer alltid att finnas 2 bilder med grafer. Den första bilden visar vad som hÀnder i allmÀnhet pÄ servern.
Och i denna situation ser vi att vi verkligen har en tabell av liten storlek. Indexet Àr litet, pÄ 2 MB. Detta Àr den första grafen till vÀnster.
Den genomsnittliga svarstiden för servern Àr ocksÄ stabil och lÄg. Detta Àr den övre grafen till höger.
Den nedersta vÀnstra grafen visar de lÀngsta transaktionerna. Vi ser att transaktionerna genomförs snabbt. Och autovakuum fungerar Ànnu inte hÀr, eftersom det var ett starttest. Framöver kommer det att fungera och vara till nytta för oss.

Den andra bilden kommer alltid att handla om den testade tabellen. I den hÀr situationen uppdaterar vi kontinuerligt saldot pÄ kundens konton. Och vi ser att den genomsnittliga svarstiden för uppdateringsoperationen Àr ganska bra, mindre Àn en millisekund. Vi ser ocksÄ att CPU-resurserna (det Àr den övre högra grafen) förbrukas jÀmnt och i ganska smÄ mÀngder.
Den nedre högra grafen visar hur mycket operativ och diskminne vi gĂ„r igenom i sökandet efter vĂ„r nödvĂ€ndiga rad innan vi uppdaterar den. Och antalet operationer pĂ„ tabellen â 2000 per sekund, precis som jag nĂ€mnde tidigare.

Och nu hÀnder det en tragedi. Av nÄgon anledning uppstÄr en lÄng glömd transaktion. Orsakerna Àr vanligtvis banala:
- En av de vanligaste situationerna Ă€r att vi i applikationskoden börjar anropa en extern tjĂ€nst. Och den tjĂ€nsten svarar inte oss. Det vill sĂ€ga, vi öppnade en transaktion, gjorde en Ă€ndring i databasen och gick för att lĂ€sa e-post i applikationen eller till en annan tjĂ€nst i vĂ„r infrastruktur, och av nĂ„gon anledning svarar den inte oss. Och vĂ„r session hĂ€nger i ett tillstĂ„nd â oklart nĂ€r det ska lösas.
- Den andra situationen Àr nÀr det i koden av nÄgon anledning uppstod ett undantag. Och vi i undantaget inte hanterade stÀngningen av transaktionen. Och vi har fÄtt en hÀngande session med en öppen transaktion.
- Och den sista â det Ă€r ocksĂ„ ett ganska vanligt fall. Det handlar om undermĂ„lig kod. Vissa ramverk öppnar en transaktion. Den hĂ€nger, och du kan vara ovetande om att den hĂ€nger i applikationen.
Vad leder sÄdana saker till?
Till att vÄra tabeller och index börjar svÀlla kraftigt. Det hÀr Àr just den effekt som kallas bloat. För databasen kommer det att innebÀra att vi fÄr en dramatisk ökning i databasens svarstid, ökad belastning pÄ databasservern. Och som ett resultat kommer applikationen att lida. För om du i koden tog 10 millisekunder för en förfrÄgan till databasen, 10 millisekunder för din logik, sÄ fungerade din funktion pÄ 20 millisekunder. Men nu kommer situationen att bli helt sorglig.
LÄt oss se vad som hÀnder. Den vÀnstra nedre grafen visar att vi har en lÄngvarig transaktion. Och om vi tittar pÄ den vÀnstra övre grafen ser vi att storleken pÄ tabellen, som var tvÄ megabyte, plötsligt har ökat till 300 megabyte. Samtidigt har mÀngden data i tabellen inte förÀndrats, dvs. det finns en stor mÀngd skrÀp.

Den övergripande situationen för medelservartid har ocksÄ förÀndrats flera gÄnger. Det vill sÀga alla förfrÄgningar till servern har börjat sjunka kraftigt. Samtidigt har interna Postgres-processer i form av autovakuum startat, som försöker göra nÄgot och förbrukar resurser.

Vad hÀnder med vÄr tabell? Samma sak. Medel svarstid för tabellen har ökat flera gÄnger. NÀr vi ser pÄ de anvÀnda resurserna, ser vi att belastningen pÄ processorn har ökat kraftigt. Det Àr den övre högra grafen. Den har ökat eftersom processorn mÄste gÄ igenom massor av vÀrdelösa rader för att hitta en enda som behövs. Det Àr den nedre högra grafen. Som ett resultat har antalet anrop per sekund börjat sjunka kraftigt eftersom databasen inte hinner bearbeta samma mÀngd förfrÄgningar.

Vi mÄste komma tillbaka till livet. Vi gÄr in pÄ internet och fÄr reda pÄ att lÄngvariga transaktioner orsakar problem. Vi hittar och dödar denna transaktion. Och nu fungerar allt som det ska. Allt fungerar bra.
Vi lugnar ner oss, men efter ett tag börjar vi mÀrka att applikationen inte fungerar som den gjorde före incidenten. FörfrÄgningar bearbetas fortfarande lÄngsammare, och faktiskt betydligt lÄngsammare. I mitt fall Àr det en och en halv till tvÄ gÄnger lÄngsammare. Belastningen pÄ servern Àr ocksÄ högre Àn den var före incidenten.

Och frÄgan Àr: "Vad hÀnder med databasen vid det tillfÀllet?". Med databasen sker följande: I grafen för transaktioner ser ni att den har stannat och det finns verkligen inga lÄngvariga transaktioner dÀr. Men storleken pÄ tabellen har under incidenten ökat katastrofalt. Och har inte minskat sedan dess. Medeltiden för databasen har stabiliserats. Svaren verkar komma fram i en acceptabel hastighet för oss. Autovakuum har blivit mer aktivt och har börjat göra nÄgot med tabellen, för det behöver bearbeta en större mÀngd data.

Specifikt för den testade fakturatabellen, dÀr vi Àndrar saldon: svarstiden pÄ förfrÄgan verkar ha ÄtergÄtt till det normala. Men i sjÀlva verket Àr den en och en halv gÄng högre.
Och nÀr det gÀller CPU-belastningen ser vi att den inte har ÄtergÄtt till rÀtt nivÄ innan kraschen. Orsaken döljer sig precis i den nedre högra grafen. Det Àr tydligt att nÄgot slags minnesöverskott sker dÀr. D.v.s. för att hitta den nödvÀndiga raden förbrukar vi serverresurser i databasen nÀr vi gÄr igenom onödiga data. Antalet transaktioner per sekund har stabiliserats.
Ăverlag Ă€r det bra, men situationen Ă€r vĂ€rre Ă€n vad den var. En tydlig nedgĂ„ng i databasen som en följd av vĂ„r applikation som arbetar med denna databas.

Och för att förstÄ vad som hÀnder dÀr, om ni inte var pÄ den föregÄende presentationen, sÄ kommer lite teori nu. Teorin om den interna processen. Vad Àr autovakuum och vad gör det?
Kort sagt för att förstÄ. Vid nÄgon tidpunkt har vi en tabell. I tabellen finns rader. Dessa rader kan vara aktiva, livliga, viktiga för oss nu. PÄ bilden Àr de markerade i grönt. Och det finns döda rader, som redan har anvÀnts, har uppdaterats, nya poster har tillkommit. De Àr markerade eftersom de inte lÀngre intresserar databasen. Men de ligger kvar i tabellen pÄ grund av PostgreSQL:s egenskaper.
Vad behövs autovakuum för? Autovakuum kommer vid nÄgot tillfÀlle, kontaktar databasen och frÄgar: "Ge mig vÀnligen id för den Àldsta transaktionen som för nÀrvarande Àr öppen i databasen." Databasen returnerar detta id. Och autovakuum, baserat pÄ detta, gÄr igenom raderna i tabellen. Om det ser att vissa rader har förÀndrats av betydligt Àldre transaktioner, har det rÀtt att markera dem som rader som vi kan ÄteranvÀnda i framtiden genom att skriva nya data dÀr. Detta Àr en bakgrundsprocess.
Under tiden fortsÀtter vi att arbeta med databasen, fortsÀtter att göra olika Àndringar i tabellen. Och pÄ dessa rader, som vi kan ÄteranvÀnda, skriver vi ny data. PÄ sÄ sÀtt fÄr vi ett kretslopp, d.v.s. hela tiden uppstÄr det döda gamla rader, istÀllet skriver vi nya rader som vi behöver. Och detta Àr ett normalt tillstÄnd för att arbeta med PostgreSQL.

Vad hÀnde under kraschen? Hur gick processen till dÀr?
Vi hade en tabell i nÄgot tillstÄnd, vissa rader levande och andra döda. Autofragmentering kom. Den frÄgade databasen om vilken som var vÄr Àldsta transaktion och vilket id den hade. Den fick det id som kan vara flera timmar gammalt eller bara tio minuter. Det beror pÄ hur hög belastning ni har i databasen. Sedan började den leta efter rader som den kan mÀrka som ÄteranvÀndbara. Men den hittade inga sÄdana rader i vÄr tabell.
Men under tiden fortsÀtter vi att arbeta med tabellen. Vi gör nÄgot i den, uppdaterar, Àndrar data. Vad har databasen att göra under tiden? Den har inget annat att göra Àn att skriva nya rader i slutet av den befintliga tabellen. PÄ sÄ sÀtt börjar storleken pÄ tabellen att öka.
För vÄrt arbete behöver vi egentligen gröna rader. Men under ett sÄdant problem fÄr vi att procentandelen gröna rader Àr extremt lÄg i hela tabellen.
NÀr vi gör en förfrÄgan mÄste databasen gÄ igenom alla rader: bÄde röda och gröna, för att hitta den nödvÀndiga raden. Effekten av att tabellen svullnar upp med onödiga data kallas 'bloat', som ocksÄ slukar vÄrt diskutrymme. Kommer ni ihÄg, det var 2 MB, nu Àr det 300 MB? Och nu, byt megabyte mot gigabyte sÄ kommer ni snabbt att förlora alla era disresurser.

Vilka konsekvenser kan det fÄ för oss?
- I mitt exempel har tabellen och indexet vuxit med 150 gÄnger. Hos vissa av vÄra kunder har det intrÀffat mer fatala fall nÀr det helt enkelt börjar ta slut pÄ diskutrymme.
- Storleken pÄ tabellerna minskar aldrig av sig sjÀlv. Autofragmentering kan i vissa fall klippa av svansen pÄ tabellen om det bara finns döda rader. Men eftersom en konstant rotation sker kan en grön rad hÀnga kvar i slutet och inte uppdateras, medan alla andra kommer att skrivas nÄgonstans i början av tabellen. Men det Àr ett sÄ osannolikt scenario att ni inte bör hoppas pÄ att er tabell kommer att minska i storlek.
- Databasen mÄste gÄ igenom hela högen av onödiga rader. Och vi slösar med disresurser, slösar med CPU-resurser och elektricitet.
- Och detta pÄverkar direkt vÄr applikation, för om vi i början anvÀnde 10 millisekunder för en begÀran, 10 millisekunder för vÄr kod, sÄ började vi under kraschen att anvÀnda en sekund för begÀran och 10 millisekunder för koden, det vill sÀga applikationens prestanda sjönk ordentligt. NÀr kraschen löstes började vi anvÀnda 20 millisekunder för begÀran och 10 millisekunder för koden. Det betyder att vi fortfarande har en prestandaförlust pÄ en och en halv gÄng. Och allt detta pÄ grund av en transaktion som fryst, möjligtvis pÄ vÄrt fel.
- Och frÄgan Àr: "Hur fÄr vi tillbaka allt?" SÄ att allt fungerar bra och begÀrningarna gÄr lika snabbt som före kraschen.

För detta finns en viss arbetscykel som genomförs.
Först mÄste vi hitta de problematiska tabellerna som har svullnat. Vi förstÄr att för vissa tabeller gÄr inspelningen mer aktivt, för andra mindre aktivt. Och för detta anvÀnds tillÀgget . Genom att installera detta tillÀgg kan du skriva frÄgor som hjÀlper dig att hitta tabeller som har svullnat kraftigt.
Efter att du har funnit dessa tabeller mĂ„ste de komprimeras. För detta finns redan verktyg. I vĂ„rt företag anvĂ€nder vi tre verktyg. Den första Ă€r den inbyggda VACUUM FULL. Den Ă€r grym, strikt och obarmhĂ€rtig, men ibland Ă€r den mycket anvĂ€ndbar. och â detta Ă€r externa verktyg för komprimering av tabeller. Och de Ă€r mer skonsamma mot databasen.
De anvÀnds beroende pÄ vad som Àr mer bekvÀmt för dig. Men jag kommer att berÀtta mer om detta i slutet. Det viktiga Àr att det finns tre verktyg. Det finns att vÀlja pÄ.
Efter att vi har gjort alla korrigeringar och sÀkerstÀllt att allt fungerar bra, mÄste vi veta hur vi hindrar denna situation i framtiden:
- Det Àr ganska enkelt att förebygga. Man behöver hÄlla koll pÄ lÀngden pÄ sessionerna pÄ mÀsterservern. SÀrskilt farliga sessioner i tillstÄndet idle in transaction. Det Àr de som precis har öppnat en transaktion, gjort nÄgot och sedan gÄtt dÀrifrÄn eller bara fryst, förlorat sig i koden.
- Och för er, som utvecklare, Àr det viktigt att testa koden vid uppkomsten av sÄdana situationer. Det Àr inte svÄrt att göra. Det kommer att vara en nyttig kontroll. Ni undviker mÄnga "barnsjukdomar" relaterade till lÄnga transaktioner.

I wanted to show you on these graphs how the table and database behavior changed after I performed a VACUUM FULL on the table. This is not in production.
The table size immediately returned to a normal working state of a few megabytes. This did not significantly affect the average response time on the server.

However, specifically for our test table, where we updated the account balances, we see that the average response time for the data update query has decreased to pre-incident levels. The CPU resources consumed for executing this query have also fallen to pre-incident levels. The bottom right graph shows that we are now finding exactly the row we need immediately, without sifting through a bunch of dead rows that existed before the table compression. The average query response time has remained approximately at the same level, but here I might have a deviation due to my hardware.

This concludes the first story. It is the most common one and happens to everyone, regardless of the client's experience or how qualified the programmers are. Sooner or later, this occurs.
The second story, where we distribute the load and optimize server resources.

- We have grown and become quite serious. We understand that we have a replica and it would be good to balance the load: write to the Master and read from the replica. This situation usually arises when we want to prepare some reports or ETL. The business is very pleased with this. It greatly desires various reports with plenty of complex analysis.
- The reports take hours, as complex analytics can't be computed in milliseconds. We, as diligent folks, write the code. We perform inserts in the application, writing to the Master and executing reports on the replica.
- We distribute the load.
- Everything works excellently. We are doing great.

And how does this situation look? Specifically on these graphs, I also added the duration of transactions from the replica. All other graphs pertain only to the Master server.
Rapporttabellen har vuxit vid det hÀr laget. Vi ser att den genomsnittliga svarstiden för servern Àr stabil. Vi noterar att det finns en lÄngvarig transaktion pÄ repliken som pÄgÄr i tvÄ timmar. Vi ser att autovakuumen arbetar lugnt och bearbetar döda rader. Allt Àr bra.

Specifikt för den aktuella tabellen fortsÀtter vi att uppdatera saldon. Vi har ocksÄ stabil svarstid för förfrÄgan och stabil resursanvÀndning. Allt Àr bra.

Allt Àr bra tills dessa rapporter börjar skjutas upp pÄ grund av konflikter med replikationen. De skjuts upp med konstant periodicitet.
Vi gÄr ut pÄ nÀtet och börjar lÀsa varför detta hÀnder. Och vi hittar en lösning.
Den första lösningen Àr att öka replikationsfördröjningen. Vi vet att vÄr rapport tar tre timmar. Vi sÀtter replikationsfördröjningen till tre timmar. Vi startar allt, men vi har fortfarande problem med att rapporterna ibland skjuts upp.
Vi vill att allt ska vara perfekt. Vi fortsĂ€tter leta. Och vi hittar en fantastisk instĂ€llning pĂ„ nĂ€tet â hot_standby_feedback. Vi aktiverar det. Hot_standby_feedback lĂ„ter oss hĂ„lla autovakuumets arbete pĂ„ Master. PĂ„ sĂ„ sĂ€tt slipper vi helt konflikter vid replikation. Allt fungerar bra med rapporterna.

Och vad hÀnder med Master-servern under tiden? Med Master-servern har vi total katastrof. Just nu observerar vi graferna nÀr jag aktiverade bÄda dessa instÀllningar. Vi ser att sessionen pÄ repliken pÄ nÄgot sÀtt börjar pÄverka situationen pÄ Master-servern. Det pÄverkar verkligen, eftersom den har pausat autovakuumet som rensar döda rader. Storleken pÄ tabellen har Äterigen skjutit i höjden. Den genomsnittliga frÄgetiden för hela databasen har ocksÄ skjutit i höjden. Autovakuumen har blivit nÄgot anstrÀngda.

Specifikt för vÄr tabell ser vi att datan ocksÄ har skjutit i höjden. ResursanvÀndningen för CPU har ocksÄ ökat kraftigt. Vi gÄr Äterigen igenom ett stort antal döda, meningslösa rader. Och svarstiden för denna tabell och antalet transaktioner har minskat.

Hur skulle det se ut om vi inte visste vad jag pratat om tidigare?
- Vi börjar leta efter problem. Om vi har stött pÄ problem i första delen vet vi att det kan bero pÄ en lÄng transaktion och vi kollar pÄ Master. Problemet finns pÄ vÄr Master. Den har problem. Den blir varm och dess Load Average nÀrmar sig hundra.
- FörfrÄgningar dÀr hÀnger sig, men vi ser inga lÄngvariga transaktioner. Och vi förstÄr inte vad som Àr fel. Vi förstÄr inte var vi ska leta.
- Vi kontrollerar serverhÄrdvaran. Kanske har vÄr raid kraschat. Kanske har ett minnesmodul brunnit. Vad som helst kan hÀnda. Men nej, servrarna Àr nya, allt fungerar utmÀrkt.
- Alla springer omkring: administratörer, utvecklare och direktören. Inget hjÀlper.
- Och plötsligt börjar allt oannonserat att ÄterstÀllas av sig sjÀlvt.

PÄ replikan har en förfrÄgan under tiden utförts och skickats ivÀg. Vi fick en rapport. Företaget Àr fortfarande nöjt. Som vi ser har vÄr tabell vÀxt igen och visar inga tecken pÄ minskning. PÄ grafen med sessioner har jag lÀmnat ett stycke av denna lÄnga transaktion frÄn replikan sÄ att ni kan bedöma hur lÄng tid det tar innan situationen stabiliseras.
Sessionen har avslutats. Och först efter en tid kommer servern mer eller mindre i ordning. Och den genomsnittliga svarstiden pÄ förfrÄgningar pÄ Master-servern normaliseras. För Àntligen har autovacuum fÄtt möjlighet att rensa upp, markera dessa döda rader. Och ju snabbt det arbetar, desto snabbare kommer vi i ordning.

PÄ den testade tabellen, dÀr vi uppdaterar saldon pÄ konton, ser vi ett exakt samma mönster. Den genomsnittliga tiden för kontouppdatering normaliseras ocksÄ gradvis. CPU-anvÀndningen minskar ocksÄ. Och antalet transaktioner per sekund ÄtergÄr till det normala. Men inte till det normala som vi hade innan avbrottet.

I vilket fall fÄr vi en prestationsförlust precis som i första fallet, en och en halv till tvÄ gÄnger, ibland Ànnu mer.
Vi verkar ha gjort allt rÀtt. Fördelat lasten. Utrustningen stÄr inte still. Vi har förnuftigt delat upp förfrÄgningarna, men ÀndÄ blev allt dÄligt.
- Ska vi inte aktivera hot_standby_feedback? Ja, det rekommenderas vanligtvis inte att aktivera det utan starka skÀl. Eftersom den hÀr instÀllningen direkt pÄverkar Master-servern och pausar autovakuumet dÀr. Om du aktiverar det pÄ en replik och glömmer bort det kan du skada Master och fÄ stora problem med applikationen.
- Ska vi öka max_standby_streaming_delay? Ja, det Àr faktiskt sÄ. Om du har en tre timmar lÄng rapport och inte vill att den ska krascha pÄ grund av replikationskonflikter, sÄ öka bara fördröjningen. LÄnga rapporter krÀver aldrig data som just nu kommit in i databasen. Om den Àr tre timmar lÄng, kör du den för nÄgon gammal dataperiod. Tre timmars fördröjning eller sex timmars fördröjning spelar ingen roll, men dÄ fÄr du stabilt dina rapporter och slipper krascher.
- SjÀlvklart mÄste vi övervaka lÄnga sessioner pÄ repliker, sÀrskilt om du har bestÀmt dig för att aktivera hot_standby_feedback pÄ repliken. För det kan hÀnda vad som helst. Vi gav denna replik till en utvecklare för att han skulle testa förfrÄgningar. Han skrev en besynnerlig förfrÄgan. Startade den och gick för att dricka te, och vi fick en överbelastad Master. Eller vi lÀt ett olÀmpligt program gÄ dit. Situationerna Àr olika. Sessioner pÄ repliker mÄste övervakas lika noggrant som pÄ Master.
- Och om du har snabba och lÄnga förfrÄgningar pÄ repliker, sÄ Àr det bÀttre att dela upp dem för belastningsfördelning. Det hÀr hÀnvisar till streaming_delay. För snabba förfrÄgningar, ha en replik med liten replikationsfördröjning. För lÄnga rapporteringsförfrÄgningar, ha en replik som kan ligga efter med 6 timmar eller en dag. Det Àr en helt normal situation.
Vi eliminerar konsekvenserna pÄ samma sÀtt:
- Vi hittar uppblÄsta tabeller.
- Och komprimerar dem med det mest lÀmpliga verktyget för oss.
Den andra historien har nu avslutats. LÄt oss gÄ vidare till den tredje historien.

OcksÄ ganska vanlig för oss, dÀr vi gör en migrering.

- Varje programprodukt vÀxer. Kraven pÄ den förÀndras. Vi vill alltid utvecklas. Och ibland hÀnder det att vi mÄste uppdatera data i tabellen, genomföra en uppdatering inom ramen för vÄr migrering för den nya funktionalitet som vi introducerar i vÄr utveckling.
- Det gamla dataformatet fungerar inte lÀngre. Anta att vi nu gÄr till den andra tabellen dÀr jag har transaktioner för dessa konton. Och sÀg att de var i rubel, men vi har beslutat att öka noggrannheten och göra det i kopecker. För detta behöver vi göra en uppdatering: fÀltet med transaktionssumman multiplicera med hundra.
- I den moderna vÀrlden anvÀnder vi automatiserade verktyg för versionskontroll av databaser. LÄt oss anta att . Vi skriver ner vÄr migration dÀr. Testar den pÄ vÄr testdatabas. Allt Àr utmÀrkt. Uppdateringen lyckas. Det blockerar arbetet under en tid, men vi fÄr den uppdaterade datan. Och vi kan köra ny funktionalitet pÄ detta. Vi har testat allt, kontrollerat. Allt Àr bekrÀftat.
- Vi genomförde planerat arbete, genomförde migrationen.

HÀr Àr migrationen med uppdateringen presenterad för er. Eftersom detta handlar om transaktioner för konton var tabellen 15 GB. Och eftersom vi uppdaterar varje rad har vi genom uppdateringen fördubblat tabellen, eftersom vi har skrivit över varje rad.

Under migrationen kunde vi inte göra nÄgot med den hÀr tabellen, eftersom alla förfrÄgningar till den köades och vÀntade pÄ att denna uppdatering skulle avslutas. Men hÀr vill jag pÄpeka siffrorna pÄ den vertikala axeln. AlltsÄ hade vi genomsnittlig förfrÄgningstid före migrationen pÄ cirka 5 millisekunder och belastning pÄ processorn, antal blockoperationer för minneslÀsning av disken mindre Àn 7,5.

Vi genomförde migrationen och fick Äterigen problem.
Migrationen lyckades, men:
- Den gamla funktionaliteten tar lÀngre tid att utföra.
- Tabellen har Äterigen vÀxt i storlek.
- Belastningen pÄ servern har Äterigen blivit större Àn den var.
- Och naturligtvis, medan vi fortfarande arbetar med den funktionalitet som fungerade bra, har vi förbÀttrat den lite grann.
Och det Àr Äterigen bloat som Äterigen försvÄrar vÄrt liv.

HÀr visar jag att tabellen, precis som i de tidigare tvÄ fallen, inte tÀnker ÄtervÀnda till sina tidigare storlekar. Den genomsnittliga belastningen pÄ servern verkar vara rimlig.

Om vi tittar pÄ tabellen med rÀkningar, sÄ ser vi att den genomsnittliga förfrÄgan har dubblats för denna tabell. Belastningen pÄ processorn och antalet rader som bearbetas i minnet har ökat till över 7,5, jÀmfört med tidigare. För processorerna har det ökat med 2 gÄnger, för blockoperationerna med 1,5 gÄnger, dvs. vi har fÄtt en degradering av serverns prestanda. Och följaktligen Àr det en degradering av prestandan för vÄr applikation. Samtidigt har antalet anrop förblivit ungefÀr pÄ samma nivÄ.

Och det viktigaste hÀr Àr att förstÄ hur man korrekt gör sÄdana migreringar. Och de mÄste göras. Vi gör dessa migreringar ganska ofta.
- SÄdana stora migreringar görs inte automatiskt. De mÄste alltid övervakas.
- Det behövs kontroll frÄn en kunnig person. Om du har en DBA i teamet, lÄt denne göra det. Det Àr deras jobb. Om inte, sÄ bör den mest erfarna personen som vet hur man arbetar med databaser göra det.
- Den nya databasschemat, Àven om vi uppdaterar en kolumn, förbereder vi alltid i steg, dvs. i förvÀg innan den nya versionen av applikationen rullas ut:
- Nya fÀlt lÀggs till dÀr vi kommer att lagra de uppdaterade data.
- Vi flyttar data frÄn det gamla fÀltet till det nya fÀltet i smÄ delar. Varför gör vi detta? För det första kontrollerar vi alltid processen under den hÀr processen. Vi vet att vi redan har flyttat sÄ och sÄ mÄnga batchar och har sÄ och sÄ mÄnga kvar.
- En annan positiv effekt Àr att vi mellan varje sÄdan batch stÀnger en transaktion, öppnar en ny, och detta ger möjligheten för autovakuumet att arbeta pÄ tabellen, mÀrka döda rader för ÄteranvÀndning.
- För rader som kommer att dyka upp under applikationens gĂ„ng (vĂ„r gamla applikation kör fortfarande) lĂ€gger vi till en trigger som skriver nya vĂ€rden i de nya fĂ€lten. I vĂ„rt fall â det innebĂ€r multiplikation med hundra av det gamla vĂ€rdet.
- Om vi Àr helt envisa och vill ha samma fÀlt, sÄ vid slutet av alla migreringar och innan vi rullar ut den nya versionen av applikationen, byter vi helt enkelt namn pÄ fÀlten. De gamla till ett pÄhittat namn och de nya fÀlten byter vi namn till gamla.
- Och först efter detta lanserar vi den nya versionen av applikationen.
Och pÄ sÄ sÀtt kommer vi inte att fÄ bloat och vi kommer inte att fÄ en sÀnkning av prestanda.
HĂ€r avslutades den tredje historien.

Och nu ska vi gÄ lite mer in pÄ verktygen som jag nÀmnde i den allra första historien.
Innan du börjar leta efter bloat, bör du definitivt installera tillÀgget .
För att ni inte ska behöva hitta pÄ frÄgorna sjÀlva, har vi redan skrivit dessa frÄgor i vÄrt arbete. Ni kan anvÀnda dem. HÀr presenteras tvÄ frÄgor.
- Den första tar ganska lÄng tid att köra, men den ger dig exakta vÀrden för bloat i tabellen.
- Den andra gĂ„r snabbare och Ă€r mycket effektiv nĂ€r du behöver göra en snabb bedömning â finns det bloat eller inte i tabellen. Och du bör ocksĂ„ förstĂ„ att bloat i en Postgres-tabell alltid finns. Det Ă€r en egenhet av dess MVCC-modell.
- Och 20 % bloat Àr normalt för tabeller i de flesta fall. Det vill sÀga, du behöver inte oroa dig och komprimera denna tabell.
Hur man identifierar tabeller som har svÀllt, det har vi klargjort, sÀrskilt nÀr de har svÀllt med onödiga data.
Nu om hur man ÄtgÀrdar bloat:
- Om vi har en liten tabell och bra diskar, det vill sÀga för en tabell under en gigabyte gÄr det bra att anvÀnda VACUUM FULL. Det kommer att ta en exklusiv lÄs pÄ tabellen i nÄgra sekunder och sen klarar det allt snabbt och effektivt. Vad gör VACUUM FULL? Det tar en exklusiv lÄs pÄ tabellen och kopierar levande rader frÄn gamla tabeller till en ny tabell. Och i slutet byter det plats pÄ dem. Gamla filer tas bort, nya sÀtts istÀllet för de gamla. Men under sin operation tar det en exklusiv lÄs pÄ tabellen. Det betyder att du inte kan göra nÄgot med denna tabell: varken skriva till den, lÀsa frÄn den eller modifiera den. Och VACUUM FULL krÀver extra diskutrymme för att lagra data.
- NÀsta verktyg . I sin funktion Àr det mycket lik VACUUM FULL, eftersom det ocksÄ kopierar data frÄn gamla filer till nya och byter ut dem i tabellen. Men det tar inte en exklusiv lÄs pÄ tabellen i början av sin operation, utan gör det först nÀr det har fÀrdiga data för att byta ut filerna. Diskresurskraven Àr liknande VACUUM FULL. Du behöver extra utrymme pÄ disken, vilket ibland kan vara kritiskt om du har terabyte-stora tabeller. Och det Àr ganska resurskrÀvande pÄ processorn, eftersom det arbetar aktivt med in- och utdata.
- Det tredje verktyget Àr . Den hanterar resurser pÄ ett mer varsamt sÀtt eftersom den fungerar enligt nÄgot andra principer. HuvudpoÀngen med pgcompacttable Àr att den vid uppdateringar flyttar alla levande rader till början av tabellen. Och sedan kör den vacuum pÄ denna tabell, eftersom vi vet att vi har levande rader i början och döda rader i slutet. Vacuum skÀr sedan bort den svansen, det vill sÀga att det inte krÀver mycket extra diskutrymme. Dessutom kan det ocksÄ optimeras för resurser.
Allt med verktygen.

Om du tycker att Àmnet med bloat Àr intressant och vill grÀva djupare, hÀr Àr nÄgra anvÀndbara lÀnkar:
- â det Ă€r en presentation av min kollega. Den handlar allmĂ€nt om vart utrymmet tar vĂ€gen i Postgres under dess arbete och liv. Och det finns en vĂ€ldigt stor och detaljerad teknisk del för databasadministratörer om bloat.
- â det Ă€r en lĂ€nk till vĂ„rt repository, dĂ€r vi lagrar en massa anvĂ€ndbara skript för att kontrollera databasens tillstĂ„nd. DĂ€r kan du hitta skript för att söka efter bloat.
- och lÀnkar till verktyg som hjÀlper dig att optimera tabeller.
- â det Ă€r ett inlĂ€gg av min kollega. DĂ€r gĂ„r han ganska seriöst och detaljerat in pĂ„ bloat pĂ„ en nivĂ„ nĂ€ra databasadministratörer.
Jag har hÀr försökt att visa en skrÀmselhicka för utvecklarna, eftersom de Àr vÄra direkta kunder till databaser och mÄste förstÄ vilka konsekvenser olika handlingar kan leda till. Jag hoppas att jag lyckades. Tack för uppmÀrksamheten!
FrÄgor
Tack för presentationen! Du pratade om hur man kan identifiera problem. Men hur kan man förhindra dem? Det vill sÀga, jag hade en situation dÀr förfrÄgningar hÀngde inte bara för att de kontaktade externa tjÀnster. Det var bara nÄgra galna joins. Det fanns nÄgra smÄ harmlösa förfrÄgningar som hÀngde i ett dygn och sedan började skapa kaos. Det liknar mycket det du beskriver. Hur kan man övervaka detta? Ska man stÀndigt sitta och kolla vilken förfrÄgan som hÀnger? Hur kan man förhindra detta?
I det hÀr fallet Àr det en uppgift för administratörerna i ditt företag, inte nödvÀndigtvis för DBA.
Jag Àr administratör.
I PostgreSQL finns det en vy som heter pg_stat_activity, dÀr hÀngande förfrÄgningar visas. Och du kan se hur lÀnge den har hÀngt dÀr.
MÄste jag gÄ in och kolla var femte minut?
StÀll in cron och kontrollera. Om du har en lÄngvarig begÀran, skriv ett mail och allt. Det vill sÀga, du behöver inte titta med ögonen, det gÄr att automatisera. Du fÄr ett mail, och du reagerar pÄ det. Eller sÄ kan du avfyra det automatiskt.
Finns det uppenbara orsaker till varför detta hÀnder?
Jag har nÀmnt nÄgra. Andra mer komplexa exempel. Och diskussionen kan ta lÄng tid.
Tack för presentationen! Jag ville klargöra kring verktyget pg_repack. Om det inte gör en exklusiv lĂ„sning, dĂ„âŠ
Det gör en exklusiv lÄsning.
⊠...kan jag potentiellt förlora data. Ska min applikation inte registrera nÄgot under den tiden?
Nej, den fungerar lugnt med tabellen, det vill sÀga pg_repack flyttar först alla levande rader som finns. SjÀlvklart sker det nÄgon registrering i tabellen. Den lÀgger bara till den sista biten.
Det vill sÀga, gör den i slutÀnden faktiskt?
I slutet tar den en exklusiv lÄsning för att byta plats pÄ de hÀr filerna.
Kommer det att gÄ snabbare Àn VACUUM FULL?
VACUUM FULL, nÀr det startade, tog direkt en exklusiv lÄsning. Och förrÀn den har gjort allt, slÀpper den den inte. Och pg_repack tar en exklusiv lÄsning endast vid tidpunkten för filbyten. Just dÄ kan du inte skriva dit, men alla data gÄr inte förlorade, allt kommer att vara i ordning.
Hej! Du pratade om hur autovacuum fungerar. Det fanns en graf med röda, gula och gröna celler. Det vill sĂ€ga, de gula â han markerade dem som raderade. Och följaktligen kan man skriva nĂ„got nytt i dem?
Ja. Postgres tar inte bort rader. Det Àr dess specifikation. Om vi uppdaterar en rad, markerar vi den gamla som raderad. DÀr sÀtts id för transaktionen som Àndrade den raden, och vi skriver in en ny rad. Och vi har sessioner som potentiellt kan lÀsa dem. Vid nÄgon tidpunkt blir de helt gamla. Och syftet med autovacuum Àr att den gÄr igenom dessa rader och markerar dem som onödiga. Och dit kan man skriva om data.
Jag förstÄr. Men frÄgan handlar lite inte om det. Jag har inte avslutat. LÄt oss anta att vi har en tabell. Den har fÀlt med variabel storlek. Och om jag försöker sÀtta in nÄgot nytt kan det kanske inte fÄ plats i den gamla cellen.
Nej, hela raden uppdateras oavsett. Postgres har tvÄ datalagermodeller. Den vÀljer baserat pÄ datatyp. Det finns data som lagras direkt i tabellen, och sÄ finns det tos-data. Det handlar om stora datamÀngder: text, json. De lagras i separata tabeller. Och i dessa tabeller hÀnder samma sak med bloat, det vill sÀga exakt samma sak. De Àr bara separerade.
Tack för presentationen! Hur acceptabelt Àr det att anvÀnda statement timeout för att begrÀnsa lÀngden pÄ förfrÄgningar?
Mycket acceptabelt. Vi anvÀnder det överallt. Och eftersom vi inte har vÄra egna tjÀnster, utan erbjuder fjÀrrsupport, sÄ finns det en ganska varierad kundbas. Alla Àr ganska nöjda med det. Det finns cron-jobb som gör kontroller. Det diskuteras helt enkelt lÀngden pÄ sessionerna med kunden, innan vi avslutar dem. Det kan vara en minut, det kan vara 10 minuter. Det beror pÄ belastningen pÄ databasen och dess syfte. Men vi anvÀnder pg_stat_activity för alla.
Tack för presentationen! Jag försöker anpassa din presentation till mina applikationer. Och det verkar som om vi alltid startar en transaktion, och alltid avslutar den. Om nÄgot undantag intrÀffar, sÄ sker rollback ÀndÄ. Och hÀr började jag fundera. En transaktion kan ju startas implicit. Det Àr nog en vink till tjejen. Om jag bara gör en uppdatering av en post, startar transaktionen i PostgreSQL och avslutas den först nÀr anslutningen kopplas ur?
Om du pratar om applikationsnivÄn nu, sÄ beror det pÄ vilken drivrutin du anvÀnder, vilken ORM som anvÀnds. Det finns mycket instÀllningar. Om auto commit Àr aktiverat dÄ startar och avslutas transaktionen direkt.
Det vill sÀga, avslutas den genast efter uppdateringen?
Det beror pÄ instÀllningarna. Jag nÀmnde en instÀllning. Denna auto commit. Den Àr ganska utbredd. Om den Àr aktiverad sÄ öppnas och stÀngs transaktionen. Om du inte uttryckligen sa "start transaction" och "end transaction", utan bara körde en frÄga i sessionen.
Hej! Tack för presentationen! TÀnk att vi har en databas som vÀxer och vÀxer och nu tar det slut pÄ utrymmet pÄ servern. Finns det nÄgra verktyg för att ÄtgÀrda denna situation?
Utrymmet pÄ servern bör helst övervakas.
Till exempel, om DBA fÄr en kopp kaffe, var pÄ semester, osv.
NÀr ett filsystem skapas, sÄ reserveras Ätminstone en del utrymme dÀr inga data skrivs.
Och om det blir helt noll?
Det kallas reserverat utrymme, vilket innebÀr att det kan frigöras och beroende pÄ hur stort det Àr, sÄ fÄr ni ledigt utrymme. Jag vet inte hur mycket det Àr som standard. I ett annat fall kan man behöva leverera diskar för att ha tillrÀckligt med utrymme för att utföra ÄterstÀllningsoperationen. Man kan ta bort en tabell som man garanterat inte behöver.
Finns det andra verktyg?
Det Àr alltid manuellt arbete. Man ser pÄ plats vad som Àr bÀst att göra, eftersom det finns kritiska och icke-kritiska data. Och för varje databas och tillÀmpning som arbetar med den beror det pÄ företaget. Beslutet fattas alltid pÄ plats.
Tack för presentationen! Jag har tvÄ frÄgor. För det första, ni visade bilder dÀr ni visade att vid hÀngande transaktioner ökar bÄde storleken pÄ tabellutrymmet och storleken pÄ indexet. Och lÀngre fram i presentationen fanns mÄnga verktyg som packar tabellen. Men vad hÀnder med indexet?
De packar ocksÄ.
Men vakuum pÄverkar inte indexet?
Vissa verktyg arbetar med indexet. Till exempel pg_rapack, pgcompacttable. Vakuum Äterskapar index, det pÄverkar dem. Syftet med VACUUM FULL Àr att skriva om allt, det arbetar med allt.
Och den andra frÄgan. Jag förstod inte varför rapporter pÄ repliker sÄ starkt beror pÄ sjÀlva replikeringen. Jag hade för mig att rapporter Àr lÀsning och replikering Àr skrivning.
Var uppstÄr konflikten vid replikering? Vi har en Master dÀr processerna sker. Vi har en autovakuumprocess. Vad gör autovakuum egentligen? Det tar bort gamla rader. Om vi har en begÀran pÄ repliken under tiden som lÀser dessa gamla rader, och pÄ Master har det hÀnt att autovakuum markerat dessa rader som möjliga för överskrivning, sÄ har vi skrivit om dem. NÀr ett paket data kommer och vi mÄste skriva om de rader som begÀran pÄ repliken behöver, dÄ kommer replikationsprocessen att vÀnta pÄ den timeout ni har stÀllt in. Sedan kommer PostgreSQL att avgöra vad som Àr viktigare för den. Och replikeringen Àr viktigare Àn begÀran, och den kommer att avbryta begÀran för att genomföra dessa Àndringar pÄ repliken.
Andrey, jag har en frĂ„ga. Ăr de hĂ€r fantastiska diagrammen du visade under presentationen resultatet av nĂ„got av dina verktyg? Hur konstruerades diagrammen?
Detta Àr en tjÀnst .
Ăr detta en kommersiell produkt?
Ja. Det Àr en kommersiell produkt.
KĂ€lla: habr.com
