Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Die verslag bied 'n paar benaderings wat dit toelaat monitor die prestasie van SQL-navrae wanneer daar miljoene van hulle per dag is, en daar is honderde beheerde PostgreSQL-bedieners.

Watter tegniese oplossings laat ons toe om so 'n volume inligting doeltreffend te verwerk, en hoe dit die lewe vir 'n gewone ontwikkelaar makliker maak.


Wie stel belang ontleding van spesifieke probleme en verskeie optimeringstegnieke SQL-navrae en die oplossing van tipiese DBA-take in PostgreSQL - jy kan ook sien reeks artikels oor hierdie onderwerp.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)
My naam is Kirill Borovikov, ek verteenwoordig die maatskappy "Tensor". Spesifiek, ek spesialiseer in die werk met databasisse in ons maatskappy.

Vandag sal ek jou vertel hoe ons besig is met navraagoptimalisering, wanneer jy nie die prestasie van 'n enkele navraag hoef te "optel" nie, maar die probleem massaal op te los. Wanneer daar miljoene versoeke is, en jy moet sommige vind benaderings tot oplossing hierdie groot probleem.

In die algemeen, "Tensor" vir 'n miljoen van ons kliënte is VLSI - ons aansoek: korporatiewe sosiale netwerk, oplossings vir videokommunikasie, vir interne en eksterne dokumentbestuur, rekeningkundige stelsels vir rekeningkunde en pakhuis, ... Dit wil sê so 'n "megakombinasie" vir geïntegreerde besigheidsbestuur, waarin daar meer as 100 verskillende interne projekte is .

Om almal van hulle normaalweg te laat werk en te ontwikkel, het ons 10 ontwikkelingsentrums regoor die land, hulle het meer 1000 ontwikkelaars.

Ons werk sedert 2008 met PostgreSQL en het 'n groot hoeveelheid van wat ons verwerk - dit is kliëntdata, statistiese, analitiese, data van eksterne inligtingstelsels - opgehoop - meer as 400 TB. Slegs "in produksie" is daar ongeveer 250 bedieners, en in totaal is daar ongeveer 1000 databasisbedieners wat ons monitor.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

SQL is 'n verklarende taal. Jy beskryf nie "hoe" iets moet werk nie, maar "wat" jy wil kry. Die DBBS weet beter hoe om 'n JOIN te doen - hoe om jou tabelle te verbind, watter voorwaardes om op te lê, wat sal deur die indeks gaan, wat sal nie ...

Sommige DBBS aanvaar wenke: "Nee, sluit by hierdie twee tafels in so en so 'n tou aan", maar PostgreSQL weet nie hoe nie. Dit is die bewuste posisie van die voorste ontwikkelaars: "Ons sal beter die navraagoptimaliseerder voltooi as om ontwikkelaars 'n paar wenke te laat gebruik."

Maar ten spyte van die feit dat PostgreSQL nie "buite" toelaat om homself te bestuur nie, laat dit dit perfek toe kyk wat binne aangaanwanneer jy jou navraag uitvoer en waar dit probleme het.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Oor die algemeen, met watter klassieke probleme kom 'n ontwikkelaar [na DBA] gewoonlik? “Hier het ons aan die versoek voldoen, en ons is stadig, alles hang, iets gebeur ... Een of ander moeilikheid!

Die redes is amper altyd dieselfde:

  • ondoeltreffende navraagalgoritme
    Die ontwikkelaar: "Nou het ek vir hom 10 tabelle in SQL deur JOIN ..." - en verwag dat sy toestande wonderbaarlik effektief sal "ontkoppel", en hy sal alles vinnig kry. Maar wonderwerke gebeur nie, en enige stelsel met sulke veranderlikheid (10 tabelle in een FROM) gee altyd 'n soort fout. [статья]
  • verouderde statistieke
    Die oomblik is baie relevant spesifiek vir PostgreSQL, wanneer jy 'n groot datastel op die bediener "uitgegooi" het, 'n versoek rig - en dit "seks skandeer" jou op die bord. Want gister was daar 10 rekords daarin, en vandag is daar 10 miljoen, maar PostgreSQL is nog nie bewus hiervan nie, en dit moet daaroor gevra word. [статья]
  • hulpbronne in te "prop".
    Jy plaas 'n groot en swaar gelaaide databasis op 'n swak bediener wat nie genoeg skyf, geheue of die werkverrigting van die verwerker self het nie. En dit is al ... Iewers is daar 'n prestasieplafon, waarbo jy nie meer kan spring nie.
  • blokkeer
    'n Moeilike oomblik, maar hulle is die mees relevant vir verskeie wysigingsnavrae (INSERT, UPDATE, DELETE) - dit is 'n aparte groot onderwerp.

Kry 'n plan

… En vir alles anders, ons 'n plan nodig! Ons moet sien wat binne die bediener aangaan.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

'n Navraaguitvoeringsplan vir PostgreSQL is 'n navraaguitvoeringsalgoritmeboom in tekstuele voorstelling. Presies die algoritme wat as die doeltreffendste erken is as gevolg van die ontleding deur die beplanner.

Elke boomnodus is 'n operasie: onttrek data uit 'n tabel of indeks, bou van 'n bitmap, verbind twee tabelle, verbind, sny of sluit keuses uit. Om 'n navraag uit te voer is 'n stap deur die nodusse van hierdie boom.

Om die navraagplan te kry, is die maklikste manier om die stelling uit te voer EXPLAIN. Om met alle werklike eienskappe te kom, d.w.s. voer eintlik 'n navraag op die basis uit - EXPLAIN (ANALYZE, BUFFERS) SELECT ....

Slegte punt: wanneer jy dit uitvoer, gebeur dit "hier en nou", so dit is slegs geskik vir plaaslike ontfouting. As jy 'n hoogs gelaaide bediener neem wat onder 'n sterk vloei van data verander, en jy sien: "Haai! Hier het ons stadig opgetreeXia versoek." 'n Halfuur, 'n uur gelede - terwyl jy besig was om hierdie versoek uit die logboeke te kry, dit terug na die bediener toe te dra, het jou hele datastel en statistiek verander. Jy hardloop dit om te ontfout - en dit loop vinnig! En jy kan nie verstaan ​​"hoekom", hoekom nie dit was stadig.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Om te verstaan ​​wat presies was op die oomblik toe die versoek op die bediener uitgevoer word, het slim mense geskryf outo_verduidelik module. Dit is teenwoordig in byna al die mees algemene PostgreSQL-verspreidings, en dit kan eenvoudig in die konfigurasielêer geaktiveer word.

As hy verstaan ​​dat die een of ander versoek langer duur as die limiet wat jy vir hom gesê het, doen hy dit "snapshot" die plan van hierdie versoek en skryf dit saam na die log.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Alles blyk nou reg te wees, ons gaan na die log en sien daar ... [voetdoek van teks]. Maar ons kan niks daaroor sê nie, behalwe vir die feit dat dit 'n uitstekende plan is, want dit het 11 ms geneem om te voltooi.

Alles blyk goed te wees - maar niks is duidelik wat eintlik gebeur het nie. Benewens die algemene tyd, sien ons niks spesiaals nie. Want kyk na so 'n "brat" gewone teks is oor die algemeen skatryk.

Maar selfs al is dit nie voor die hand liggend nie, al is dit ongerieflik, is daar meer fundamentele probleme:

  • Die nodus dui aan som oor die hulpbronne van die hele subboom onder hom. Dit wil sê, dit is eenvoudig onmoontlik om uit te vind hoeveel tyd spesifiek hier aan hierdie Indeksskandering bestee is - dit is onmoontlik as daar een of ander geneste toestand daaronder is. Ons moet dinamies kyk of daar "kinders" en voorwaardelike veranderlikes binne, CTE is - en dit alles "in die verstand" aftrek.
  • Die tweede punt: die tyd wat op die nodus aangedui word, is nodus uitvoering tyd. As hierdie nodus verskeie kere uitgevoer is as gevolg van, byvoorbeeld, 'n siklus deur tabelrekords, dan verhoog die plan die aantal lusse - siklusse van hierdie nodus. Maar die atoom-uitvoeringstyd self bly dieselfde in die plan. Dit wil sê, om te verstaan ​​hoeveel hierdie knoop in totaal uitgevoer is, moet 'n mens een met die ander vermenigvuldig - weer "in die gees".

In sulke scenario's, verstaan ​​"Wie is die swakste skakel?" feitlik onrealisties. Daarom skryf selfs die ontwikkelaars self in die "handleiding" dit "Om die plan te verstaan ​​is 'n kuns wat aangeleer moet word, 'n ervaring ...".

Maar ons het 1000 ontwikkelaars, en hierdie ervaring kan nie aan elkeen van hulle oorgedra word nie. Ek, jy, hy - hulle weet, maar iemand daar oorkant - nie meer nie. Miskien sal hy leer, of dalk nie, maar hy moet nou werk – en waar sou hy hierdie ervaring vandaan kry.

Beplan visualisering

Daarom het ons besef dat ons nodig het om hierdie probleme te hanteer goeie visualisering van die plan. [artikel]

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Ons het eers "op die mark" gegaan - kom ons kyk op die internet vir wat algemeen bestaan.

Maar dit het geblyk dat daar baie min relatief "lewendige" oplossings is wat min of meer ontwikkel is - letterlik, een ding: verduidelik.depesz.com deur Hubert Lubaczewski. By die ingang van die veld "voer" die teksvoorstelling van die plan, dit wys jou 'n bord met ontleed data:

  • eie nodus verwerkingstyd
  • totale tyd oor die hele subboom
  • die aantal rekords wat herwin is en wat statisties verwag is
  • nodus liggaam self

Hierdie diens het ook die vermoë om 'n argief van skakels te deel. Jy het jou plan daar gegooi en gesê: "Haai, Vasya, hier is 'n skakel vir jou, iets is fout daar."

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Maar daar is ook klein probleme.

Eerstens 'n groot hoeveelheid "copy-paste". Jy neem 'n stuk van die stomp, sit dit daarin, en weer, en weer.

Tweede, die geen ontleding van die hoeveelheid data wat gelees is nie - dieselfde buffers wat uitvoer EXPLAIN (ANALYZE, BUFFERS), ons sien dit nie hier nie. Hy weet eenvoudig nie hoe om hulle uitmekaar te haal, te verstaan ​​en daarmee saam te werk nie. Wanneer jy baie data lees en besef dat jy dalk nie reg oor skyf en in-geheue-kas ontbind nie, is hierdie inligting baie belangrik.

Die derde negatiewe punt is die baie swak ontwikkeling van hierdie projek. Die commits is baie klein, dit is goed as een keer elke ses maande, en die kode is in Perl.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Maar dit is alles “lirieke”, mens sou op een of ander manier hiermee kon saamleef, maar daar is een ding wat ons weggedraai het van hierdie diens. Dit is Common Table Expression (CTE) ontledingsfoute en verskeie dinamiese nodusse soos InitPlan/SubPlan.

As jy hierdie prentjie glo, dan is die totale uitvoeringstyd van elke individuele nodus groter as die totale uitvoeringstyd van die hele versoek. Alles is eenvoudig - die tyd van opwekking van hierdie CTE is nie van die CTE Scan node afgetrek nie. Daarom weet ons nie meer die korrekte antwoord nie, hoe lank het die CTE-skandering self geneem.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Toe besef ons dis tyd om ons eie te skryf – hoera! Elke ontwikkelaar sê: "Nou sal ons ons eie skryf, dit sal baie maklik wees!"

Ons het 'n stapel geneem wat tipies is vir webdienste: die kern op Node.js + Express, getrek op Bootstrap en D3.js vir pragtige diagramme. En ons verwagtinge was ten volle geregverdig - ons het die eerste prototipe in 2 weke ontvang:

  • pasgemaakte plan-ontleder
    Dit wil sê, nou kan ons enige plan in die algemeen ontleed uit dié wat deur PostgreSQL gegenereer word.
  • korrekte ontleding van dinamiese nodusse - CTE Scan, InitPlan, SubPlan
  • buffer verspreiding analise - waar databladsye uit die geheue gelees word, waar vanaf die plaaslike kas, waar vanaf skyf
  • sigbaarheid gekry het
    Om nie alles in die log te “grawe” nie, maar om die “swakste skakel” dadelik in die prentjie te sien.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Ons het iets soos hierdie prent gekry – dadelik met sintaksis-uitlig. Maar gewoonlik werk ons ​​ontwikkelaars nie meer met 'n volledige voorstelling van die plan nie, maar met iets wat korter is. Ons het immers al die nommers ontleed en na links en regs gegooi, en net die eerste reël in die middel gelaat, watter soort nodus is dit: CTE Scan, CTE generasie of Seq Scan volgens een of ander plaat.

Dit is die verkorte voorstelling wat ons noem plan sjabloon.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Wat anders sou gerieflik wees? Dit sal gerieflik wees om te sien watter deel van die totale tyd na watter nodus versprei word - en ons het dit eenvoudig aan die kant "gegom" sirkelgrafiek.

Ons wys na die nodus en sien - dit blyk dat Seq Scan minder as 'n kwart van die totale tyd geneem het, en die oorblywende 3/4 is deur CTE Scan geneem. Gruwel! Dit is 'n klein nota oor die "vuurtempo" van CTE Scan, as jy dit aktief in jou navrae gebruik. Hulle is nie baie vinnig nie - hulle verloor selfs met 'n gereelde tafelskandering. [artikel] [artikel]

Maar gewoonlik is sulke diagramme interessanter, meer ingewikkeld, wanneer ons dadelik na 'n segment wys, en ons sien byvoorbeeld dat sommige Seq Scan meer as die helfte van die tyd "geëet" het. Boonop was daar 'n soort filter binne, baie rekords is daaroor weggegooi ... Jy kan hierdie prentjie direk vir die ontwikkelaar gooi en sê: "Vasya, alles is sleg hier! Vind dit uit, kyk - iets is fout!

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Natuurlik, sonder die "hark" kon nie doen nie.

Die eerste ding waarop hulle “getrap” het, was die probleem van afronding. Die nodustyd van elke individuele nodus in die plan word met 'n akkuraatheid van 1 µs aangedui. En wanneer die aantal nodusiklusse byvoorbeeld 1000 oorskry - na uitvoering, het PostgreSQL verdeel "tot", dan kry ons die totale tyd "iewers tussen 0.95ms en 1.05ms" wanneer ons agteruit bereken. Wanneer die telling na mikrosekondes gaan, is dit steeds niks, maar wanneer dit reeds na [milli] sekondes is, moet jy hierdie inligting in ag neem wanneer jy hulpbronne "ontdraai" volgens die nodusse van die plan "wie het hoeveel van wie verbruik het".

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Die tweede punt, meer ingewikkeld, is die verspreiding van hulpbronne (daardie buffers) tussen dinamiese nodusse. Dit het ons nog 2 weke gekos vir die eerste 4 weke vir die prototipe.

Dit is redelik maklik om so 'n probleem te kry - ons doen CTE en lees kwansuis iets daarin. Trouens, PostgreSQL is “slim” en sal niks direk daar lees nie. Dan neem ons die eerste rekord daarvan, en die honderd-en-eerste van dieselfde CTE daarheen.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Ons kyk na die plan en verstaan ​​- vreemd genoeg het ons 3 buffers (databladsye) "verbruik" in Seq Scan, nog 1 in CTE Scan, en nog 2 in die tweede CTE Scan. Dit wil sê, as ons alles eenvoudig opsom, kry ons 6, maar van die tablet lees ons net 3! CTE Scan lees niks van enige plek af nie, maar werk direk met die prosesgeheue. So iets is duidelik fout hier!

Om die waarheid te sê, dit blyk dat hier al daardie 3 bladsye se data wat van Seq Scan aangevra is, eers 1 gevra het vir die 1ste CTE Scan, en dan die 2de, en nog 2 daarheen gelees is. Dit wil sê, 'n totaal van 3 bladsye is gelees data, nie 6 nie.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

En hierdie prentjie het ons laat verstaan ​​dat die uitvoering van die plan nie meer 'n boom is nie, maar net 'n soort asikliese grafiek. En ons het iets soos hierdie diagram gekry sodat ons verstaan ​​"iets waarvandaan dit hoegenaamd gekom het." Dit wil sê, hier het ons 'n CTE van pg_class geskep, en dit twee keer gevra, en amper die hele tyd het dit ons langs die tak geneem toe ons die 2de keer daarvoor gevra het. Dit is duidelik dat die lees van die 101ste inskrywing baie duurder is as net die 1ste van die tabel.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Ons haal 'n rukkie asem. Het gesê: "Nou, Neo, jy ken kung fu! Nou is ons ervaring reg op jou skerm. Nou kan jy dit gebruik." [artikel]

Log Konsolidasie

Ons 1000 ontwikkelaars het 'n sug van verligting gesug. Maar ons het verstaan ​​dat ons net honderde "geveg"-bedieners het, en al hierdie "kopieer-plak" aan die kant van die ontwikkelaars is glad nie gerieflik nie. Ons het besef dat ons dit self moet afhaal.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Oor die algemeen is daar 'n gereelde module wat statistieke kan insamel, maar dit moet ook in die konfigurasie geaktiveer word - hierdie pg_stat_statements module. Maar hy het ons nie gepas nie.

Eerstens ken hy aan dieselfde navrae toe onder verskillende skemas binne dieselfde databasis verskillende QueryIds. Dit is, as jy dit eers doen SET search_path = '01'; SELECT * FROM user LIMIT 1;en dan SET search_path = '02'; en dieselfde navraag, dan sal daar verskillende inskrywings in die statistieke van hierdie module wees, en ek sal nie algemene statistieke spesifiek in die konteks van hierdie navraagprofiel kan insamel, sonder om skemas in ag te neem nie.

Die tweede punt wat ons verhinder het om dit te gebruik - gebrek aan planne. Dit wil sê, daar is geen plan nie, daar is net die versoek self. Ons sien wat vertraag het, maar verstaan ​​nie hoekom nie. En hier keer ons terug na die probleem van 'n vinnig veranderende datastel.

En die laaste oomblik - gebrek aan "feite". Dit wil sê, jy kan nie 'n spesifieke geval van navraaguitvoering aanspreek nie - dit bestaan ​​nie, daar is slegs saamgestelde statistieke. Alhoewel dit moontlik is om hiermee te werk, is dit net baie moeilik.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Daarom het ons besluit om teen "copy-paste" te veg en begin skryf versamelaar.

Die versamelaar koppel via SSH, "trek" 'n veilige verbinding na die bediener met die databasis met behulp van 'n sertifikaat, en tail -F "kleef" daaraan op die loglêer. So in hierdie sessie ons kry 'n volledige "spieël" van die hele loglêer, wat deur die bediener gegenereer word. Terselfdertyd is die las op die bediener self minimaal, want ons ontleed niks daar nie, ons weerspieël net die verkeer.

Aangesien ons reeds die koppelvlak in Node.js begin skryf het, het ons voortgegaan om die versamelaar daarop te skryf. En hierdie tegnologie het homself geregverdig, want dit is baie gerieflik om JavaScript te gebruik om met lig geformateerde teksdata te werk, wat die log is. En die Node.js-infrastruktuur self as 'n backend-platform maak dit maklik en gerieflik om met netwerkverbindings te werk, en inderdaad met 'n soort datastrome.

Gevolglik "rek" ons twee verbindings: die eerste, om na die log self te "luister" en dit na onsself te neem, en die tweede, om die basis periodiek te vra. "Maar in die log het dit opgekom dat die tablet met oid 123 geblokkeer is," maar dit beteken niks vir die ontwikkelaar nie, en dit sal lekker wees om die basis te vra "Wat is OID = 123 in elk geval?" En so vra ons van tyd tot tyd die basis wat ons nog nie weet nie.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

"Net een ding wat jy uitgelaat het, daar is 'n spesie olifantagtige bye! .." Ons het hierdie stelsel begin ontwikkel toe ons 10 bedieners wou monitor. Die mees kritieke in ons begrip, waarop sommige probleme ontstaan ​​het wat moeilik was om te hanteer. Maar gedurende die eerste kwartaal het ons honderd vir monitering ontvang - omdat die stelsel "ingekom" het, almal wou dit hê, dit is gerieflik vir almal.

Dit alles moet opgetel word, die datavloei is groot, aktief. Eintlik, wat ons monitor, wat ons weet hoe om te hanteer, ons gebruik dit. Ons gebruik ook PostgreSQL as 'n datawinkel. En niks is vinniger om data daarin te "gooi" as die operateur nie COPY Nog nie.

Maar bloot om data te “skiet” is nie juis ons tegnologie nie. Want as jy ongeveer 50k versoeke per sekonde op honderd bedieners het, sal dit 100-150GB logs per dag vir jou genereer. Daarom moes ons die basis versigtig “sny”.

Eerstens het ons dit gedoen verdeling deur die dag, want oor die algemeen stel niemand belang in die korrelasie tussen dae nie. Watter verskil maak dit wat jy gister gehad het, as jy vanaand 'n nuwe weergawe van die toepassing ontplooi het - en reeds 'n paar nuwe statistieke.

Tweedens het ons geleer (is gedwing) baie baie vinnig om mee te skryf COPY. Dit wil sê, nie net nie COPYwant dit is vinniger as INSERT, en selfs vinniger.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Die derde oomblik – ek moes weier snellers, onderskeidelik, en van Foreign Keys. Dit wil sê, ons het glad nie referensiële integriteit nie. Want as jy 'n tabel het wat 'n paar FK'e daarop het, en jy sê in die databasisstruktuur dat "hier is 'n loginskrywing wat deur FK verwys word, byvoorbeeld, na 'n groep inskrywings", dan wanneer jy dit invoeg, PostgreSQL word gelaat met niks anders as hoe om te neem en eerlik uit te voer nie SELECT 1 FROM master_fk1_table WHERE ... met die identifiseerder wat jy probeer invoeg - net om seker te maak dat hierdie inskrywing daar teenwoordig is, dat jy nie hierdie Buitelandse Sleutel "afbreek" met jou invoeging nie.

Ons kry in plaas van een rekord in die teikentabel en sy indekse, plus lees uit alle tabelle waarna dit verwys. En ons het dit glad nie nodig nie - ons taak is om soveel as moontlik en so vinnig as moontlik met die minste vrag op te neem. So FK - weg daarmee!

Die volgende punt is samevoeging en hashing. Aanvanklik het ons dit in die databasis geïmplementeer - dit is immers gerieflik om dadelik, wanneer die rekord opdaag, dit op 'n soort tablet te maak "plus een" reg in die sneller. Goed, gerieflik, maar sleg op dieselfde manier - jy voeg een rekord in, maar jy word gedwing om iets anders uit 'n ander tabel te lees en te skryf. Boonop, nie net om te lees en skryf nie - ook om dit elke keer te doen.

Stel jou nou voor dat jy 'n tabel het waarin jy eenvoudig die aantal versoeke tel wat deur 'n spesifieke gasheer gegaan het: +1, +1, +1, ..., +1. En jy het dit in beginsel nie nodig nie - dit is alles moontlik som in geheue op die versamelaar en stuur in een slag na die basis +10.

Ja, in die geval van een of ander wanfunksie, kan jou logiese integriteit "uitmekaar val", maar dit is 'n byna onrealistiese geval - want jy het 'n normale bediener, dit het 'n battery in die beheerder, jy het 'n transaksielog, 'n log op die lêerstelsel ... Oor die algemeen is dit nie die moeite werd nie. Dit is nie die prestasieverlies werd wat jy kry met snellers/FK's vir die koste wat jy aangaan nie.

Dieselfde geld vir hashing. 'n Sekere versoek vlieg na jou toe, jy bereken 'n sekere identifiseerder daaruit in die databasis, skryf dit na die databasis en vertel dit dan vir almal. Alles is reg totdat daar ten tyde van die opname 'n tweede persoon na jou toe kom wat dit self wil opneem - en jy het 'n blokkasie, en dit is reeds erg. Daarom, as jy die generering van sommige ID's aan die kliënt kan oordra (relatief tot die basis), is dit beter om dit te doen.

Dit was net perfek vir ons om MD5 uit die teks te gebruik - versoek, plan, sjabloon, ... Ons bereken dit aan die kant van die versamelaar, en "gooi" 'n klaargemaakte ID in die databasis. Die MD5-lengte en daaglikse verdeling laat ons nie bekommerd wees oor moontlike botsings nie.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Maar om dit alles vinnig op te neem, moes ons die opnameprosedure self verander.

Hoe word data gewoonlik geskryf? Ons het 'n soort datastel, ons ontbind dit in verskeie tabelle, en dan COPY - eers in die eerste, dan in die tweede, in die derde ... Dit is ongerieflik, want dit lyk of ons een datastroom in drie stappe opeenvolgend skryf . Onaangenaam. Kan dit vinniger gedoen word? Kan!

Om dit te doen, is dit genoeg om net hierdie vloei parallel met mekaar te ontbind. Dit blyk dat ons foute het, versoeke, sjablone, slotte wat in aparte drade vlieg, ... - en ons skryf dit alles parallel. Hiervoor is dit genoeg hou 'n permanent oop COPY-kanaal na elke individuele teikentabel.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Dit wil sê die versamelaar daar is altyd 'n stroom, waarin ek die data kan skryf wat ek benodig. Maar sodat die databasis hierdie data kan sien, en iemand nie in slotte kan hang nie, en wag dat hierdie data geskryf word, KOPIE moet met sekere tussenposes onderbreek word. Vir ons het die tydperk van die orde van 100ms die doeltreffendste geblyk te wees - ons maak dit toe en maak dit dadelik weer oop na dieselfde tafel. En as ons nie genoeg van een stroom by sommige pieke het nie, dan poel ons tot 'n sekere limiet.

Daarbenewens het ons uitgevind dat vir so 'n lasprofiel enige samevoeging, wanneer rekords in pakkies versamel word, sleg is. Klassieke boosheid is INSERT ... VALUES en verdere 1000 rekords. Want op daardie stadium het jy 'n skryfpiek op die media, en almal wat probeer om iets op skyf te skryf, sal wag.

Om van sulke afwykings ontslae te raak, moet net niks bymekaarmaak nie, moet glad nie buffer nie. En as buffering na skyf wel plaasvind (gelukkig laat die Stream API in Node.js jou toe om uit te vind) - stel hierdie verbinding uit. Dit is wanneer 'n gebeurtenis na jou toe kom dat dit weer gratis is - skryf daarna uit die opgehoopte tou. Intussen is dit besig – neem die volgende gratis een uit die swembad en skryf daaraan.

Voordat ons hierdie benadering tot die skryf van data geïmplementeer het, het ons ongeveer 4K skryfoperasies gehad, en op hierdie manier het ons die las met 4 keer verminder. Nou het hulle nog 6 keer gegroei as gevolg van nuwe gemonitorde databasisse – tot 100MB/s. En nou stoor ons logs vir die afgelope 3 maande in 'n hoeveelheid van ongeveer 10-15TB, met die hoop dat enige ontwikkelaar enige probleem binne drie maande kan oplos.

Ons verstaan ​​die probleme

Maar om net al hierdie data te versamel is goed, nuttig, toepaslik, maar nie genoeg nie - jy moet dit verstaan. Want dit is miljoene verskillende planne per dag.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Maar miljoene is onbeheerbaar, jy moet eers “kleiner” maak. En eerstens moet jy besluit hoe jy hierdie "kleiner" een sal organiseer.

Ons het drie sleutelpunte vir onsself geïdentifiseer:

  • wat het hierdie versoek gestuur
    Dit wil sê, van watter toepassing dit “aangekom” het: webkoppelvlak, backend, betalingstelsel of iets anders.
  • waar Dit het gebeur
    Op watter spesifieke bediener. Want as jy verskeie bedieners onder een toepassing het, en skielik een "afstomp" (omdat die "skyf vrot is", "geheue uitgelek", 'n ander probleem), dan moet jy spesifiek die bediener aanspreek.
  • hoe die probleem het op een of ander manier gemanifesteer

Om te verstaan ​​"wie" het vir ons 'n versoek gestuur, gebruik ons ​​'n gereelde hulpmiddel - stel 'n sessieveranderlike in: SET application_name = '{bl-host}:{bl-method}'; - ons stuur die naam van die besigheidslogika-gasheer waarvandaan die versoek kom, en die naam van die metode of toepassing wat dit geïnisieer het.

Nadat ons die "meester" van die versoek geslaag het, moet dit in die log vertoon word - hiervoor konfigureer ons die veranderlike log_line_prefix = ' %m [%p:%v] [%d] %r %a'. Wie gee om dalk kyk in die handleidingwat dit alles beteken. Dit blyk dat ons in die log sien:

  • tyd
  • proses- en transaksie-ID's
  • basis naam
  • Die IP van die persoon wat hierdie versoek gestuur het
  • en metode naam

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Verder het ons besef dat dit nie baie interessant is om na die korrelasie vir een versoek tussen verskillende bedieners te kyk nie. Selde kry jy 'n situasie waar jy een aansoek ewe "crap" hier en daar het. Maar selfs al is dit dieselfde – kyk na enige van hierdie bedieners.

So, sny "een bediener - een dag" ons het genoeg gevind vir enige ontleding.

Die eerste analitiese gedeelte is dieselfde "monster" - 'n verkorte vorm van die planaanbieding, skoongemaak van alle numeriese aanwysers. Die tweede snit is die toepassing of metode, en die derde is die spesifieke plannodus wat ons probleme veroorsaak het.

Toe ons van konkrete gevalle na sjablone beweeg het, het ons twee voordele gelyk:

  • meervoudige vermindering in die aantal voorwerpe vir ontleding
    Ons moet die probleem nie meer deur duisende versoeke of planne ontleed nie, maar deur dosyne patrone.
  • tydlyn
    Dit wil sê, deur die "feite" binne 'n sekere afdeling op te som, kan 'n mens hul voorkoms gedurende die dag vertoon. En hier kan jy verstaan ​​dat as jy een of ander patroon het wat byvoorbeeld een keer 'n uur gebeur, maar dit moet - een keer 'n dag, moet jy dink oor wat verkeerd geloop het - deur wie en hoekom dit genoem is, miskien moet dit hier wees behoort nie. Dit is nog 'n nie-numeriese, suiwer visuele manier van analise.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Die oorblywende metodes is gebaseer op die aanwysers wat ons uit die plan onttrek: hoeveel keer so 'n patroon plaasgevind het, die totale en gemiddelde tyd, hoeveel data van die skyf gelees is, en hoeveel uit die geheue ...

Omdat jy byvoorbeeld na die gasheer-analise-bladsy kom, kyk - iets is te veel om op die skyf te lees. Die skyf op die bediener kan dit nie hanteer nie - en wie lees daarvan?

En jy kan volgens enige kolom sorteer en besluit waarmee jy nou gaan handel - met die las op die verwerker of op die skyf, of met die totale aantal versoeke ... Gesorteer, na die "top" gekyk, dit reggemaak - 'n nuwe weergawe van die toepassing ontplooi.
[video lesing]

En dadelik kan jy verskillende toepassings sien wat met dieselfde sjabloon pas vanaf 'n versoek soos SELECT * FROM users WHERE login = 'Vasya'. Voorkant, agterkant, verwerking... En jy wonder hoekom verwerking die gebruiker moet lees as hy nie met hom interaksie het nie.

Die omgekeerde manier is van die toepassing om dadelik te sien wat dit doen. Byvoorbeeld, die frontend is dit, dit, dit, en dit een keer per uur (net die tydlyn help). En die vraag ontstaan ​​dadelik - dit blyk dat dit nie die saak van die frontend is om een ​​keer per uur iets te doen nie ...

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Na 'n geruime tyd het ons besef dat ons 'n tekort het aan 'n totaal statistieke volgens plan nodusse. Ons het van die planne slegs daardie nodusse geïsoleer wat iets met die data van die tabelle self doen (lees / skryf dit volgens indeks of nie). Trouens, met betrekking tot die vorige prentjie, word slegs een aspek bygevoeg - hoeveel rekords hierdie nodus vir ons gebring het, en hoeveel weggegooi is (rye verwyder deur filter).

Jy het nie 'n geskikte indeks op die plaat nie, jy rig 'n versoek daarvoor, dit vlieg verby die indeks, val in die Seq Scan ... jy het al die rekords gefiltreer behalwe een. En hoekom het jy 100M gefiltreerde rekords per dag nodig, is dit nie beter om die indeks op te rol nie?

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Nadat ons al die planne volgens nodusse ontleed het, het ons besef dat daar 'n paar tipiese strukture in die planne is wat heel waarskynlik verdag lyk. En dit sal lekker wees om vir die ontwikkelaar te sê: "Vriend, hier lees jy eers volgens indeks, sorteer dan en sny dan af" - as 'n reël is daar een inskrywing.

Almal wat versoeke geskryf het, het waarskynlik so 'n patroon teëgekom: "Gee my die laaste bestelling vir Vasya, sy datum." En as jy nie 'n indeks volgens datum het nie, of daar is geen datum in die indeks wat jy gebruik het nie, stap dan op presies so 'n "hark" .

Maar ons weet dat dit 'n "hark" is - so hoekom nie dadelik vir die ontwikkelaar sê wat hy moet doen nie. Gevolglik, as ons die plan nou oopmaak, sien ons ontwikkelaar dadelik 'n pragtige prentjie met wenke, waar hy dadelik gesê word: "Jy het probleme hier en daar, maar hulle word so en dat opgelos."

Gevolglik het die hoeveelheid ondervinding wat nodig was om probleme aan die begin en nou op te los, aansienlik gedaal. Hier het ons so 'n hulpmiddel.

Massa-optimering van PostgreSQL-navrae. Kirill Borovikov (Tensor)

Bron: will.com

Voeg 'n opmerking