PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Ziņojumā ir izklāstītas dažas pieejas, kas ļauj uzraudzīt SQL vaicājumu veiktspēju, ja to dienā ir miljoniem, un ir simtiem uzraudzītu PostgreSQL serveru.

Kādi tehniskie risinājumi ļauj efektīvi apstrādāt Ŕādu informācijas apjomu un kā tas atvieglo vienkārŔa izstrādātāja dzīvi?


Kuram tas interesē? specifisku problēmu analÄ«ze un dažādas optimizācijas metodes SQL vaicājumi un tipisku DBA problēmu risināŔana programmā PostgreSQL ā€” arÄ« jÅ«s varat izlasi rakstu sēriju par Å”o tēmu.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)
Mani sauc Kirils Borovikovs, es pārstāvu Uzņēmums Tensor. Konkrēti, es specializējos darbā ar datu bāzēm mūsu uzņēmumā.

Å odien es jums pastāstÄ«Å”u, kā mēs optimizējam vaicājumus, kad jums nav ā€œjāizŔķirā€ viena vaicājuma veiktspēja, bet gan jāatrisina problēma masveidā. Kad ir miljoniem pieprasÄ«jumu, un jums tie ir jāatrod pieejas risinājumam Ŕī lielā problēma.

Kopumā Tensor miljoniem mÅ«su klientu ir VLSI ir mÅ«su lietojumprogramma: korporatÄ«vais sociālais tÄ«kls, risinājumi video komunikācijai, iekŔējai un ārējai dokumentu apritei, uzskaites sistēmas grāmatvedÄ«bai un noliktavām,... RespektÄ«vi, tāds ā€œmegakombainsā€ integrētai biznesa vadÄ«bai, kurā ir vairāk nekā 100 dažādu iekŔējie projekti.

Lai nodroÅ”inātu, ka tie visi strādā un attÄ«stās normāli, mums ir 10 attÄ«stÄ«bas centri visā valstÄ«, un tajos ir vēl vairāk 1000 izstrādātāju.

Mēs strādājam ar PostgreSQL kopÅ” 2008. gada un esam uzkrājuÅ”i lielu daudzumu no tā, ko apstrādājam - klientu datus, statistiskos, analÄ«tiskos, datus no ārējām informācijas sistēmām - vairāk nekā 400 TB. RažoÅ”anā vien ir aptuveni 250 serveru, un kopumā ir aptuveni 1000 datu bāzes serveru, kurus mēs uzraugām.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

SQL ir deklaratÄ«va valoda. JÅ«s aprakstāt nevis "kā" kaut kam vajadzētu darboties, bet gan "ko" vēlaties sasniegt. DBVS labāk zina, kā izveidot JOIN ā€” kā savienot tabulas, kādus nosacÄ«jumus uzlikt, kas tiks rādÄ«ts, kas nē...

Dažas DBVS pieņem ieteikumus: ā€œNē, savienojiet Ŕīs divas tabulas tādā un tādā rindāā€, taču PostgreSQL to nevar izdarÄ«t. Tā ir vadoÅ”o izstrādātāju apzināta nostāja: ā€œMēs labprātāk pabeigsim vaicājumu optimizētāju, nevis ļautu izstrādātājiem izmantot kādus mājienus.ā€

Bet, neskatoties uz to, ka PostgreSQL neļauj ā€œÄrējaiā€ sevi kontrolēt, tas lieliski atļauj redzēt, kas notiek viņākad izpildāt vaicājumu un kur ar to rodas problēmas.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Ar kādām klasiskām problēmām parasti nāk [uz DBA] izstrādātājs? ā€œÅ eit mēs izpildÄ«jām lÅ«gumu, un pie mums viss notiek lēni, viss karājas, kaut kas notiek... Kaut kādas nepatikÅ”anas!ā€

Iemesli gandrīz vienmēr ir vienādi:

  • neefektÄ«vs vaicājuma algoritms
    Izstrādātājs: "Tagad es viņam dodu 10 tabulas SQL, izmantojot JOIN..." - un sagaida, ka viņa nosacÄ«jumi brÄ«numainā kārtā tiks efektÄ«vi "atsaistÄ«ti" un viņŔ visu ātri iegÅ«s. Bet brÄ«numi nenotiek, un jebkura sistēma ar tādu mainÄ«gumu (10 tabulas vienā FROM) vienmēr dod kaut kādu kļūdu. [raksts]
  • novecojusi statistika
    Å is punkts ir ļoti bÅ«tisks tieÅ”i PostgreSQL, kad jÅ«s "ielej" lielu datu kopu uz serveri, veicat pieprasÄ«jumu, un tas "sekskanizē" jÅ«su planÅ”etdatoru. Jo vakar tajā bija 10 ieraksti un Å”odien 10 miljoni, bet PostgreSQL to vēl nezina, un mums tas par to jāpastāsta. [raksts]
  • "pieslēgt" resursiem
    Jūs esat instalējis lielu un smagi noslogotu datubāzi vājā serverī, kuram nav pietiekami daudz diska, atmiņas vai procesora veiktspējas. Un tas arī viss... Kaut kur ir snieguma griesti, virs kuriem vairs nevar uzlēkt.
  • bloÄ·Ä“Å”ana
    Tas ir sarežģīts punkts, taču tie visvairāk attiecas uz dažādiem modificējoÅ”iem vaicājumiem (INSERT, UPDATE, DELETE) - Ŕī ir atseviŔķa liela tēma.

Plāna iegūŔana

...Un par visu pārējo mēs vajag plānu! Mums jāredz, kas notiek servera iekÅ”ienē.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

PostgreSQL vaicājuma izpildes plāns ir vaicājuma izpildes algoritma koks teksta attēlojumā. TieÅ”i algoritms plānotāja veiktās analÄ«zes rezultātā tika atzÄ«ts par visefektÄ«vāko.

Katrs koka mezgls ir darbÄ«ba: datu izgÅ«Å”ana no tabulas vai indeksa, bitkartes izveidoÅ”ana, divu tabulu savienoÅ”ana, atlases savienoÅ”ana, krustoÅ”anās vai izslēgÅ”ana. Vaicājuma izpilde ietver staigāŔanu pa Ŕī koka mezgliem.

Lai iegÅ«tu vaicājuma plānu, vienkārŔākais veids ir izpildÄ«t paziņojumu EXPLAIN. Lai iegÅ«tu visus reālos atribÅ«tus, tas ir, lai faktiski izpildÄ«tu vaicājumu bāzē - EXPLAIN (ANALYZE, BUFFERS) SELECT ....

Sliktā daļa: palaižot to, tas notiek "Å”eit un tagad", tāpēc tas ir piemērots tikai vietējai atkļūdoÅ”anai. Ja izmantojat ļoti noslogotu serveri, kurā notiek spēcÄ«ga datu izmaiņu plÅ«sma, un redzat: ā€œAk! Å eit mums ir lēna izpildexia pieprasÄ«jums." Pirms pusstundas, pirms stundas ā€” kamēr jÅ«s darbojāties un saņēmāt Å”o pieprasÄ«jumu no žurnāliem, nogādājot to atpakaļ uz serveri, tika mainÄ«ta visa jÅ«su datu kopa un statistika. Palaižat to, lai atkļūdotu ā€” un tas darbojas ātri! Un tu nevari saprast, kāpēc, kāpēc tas bija lēnām.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Lai saprastu, kas notika tieÅ”i tajā brÄ«dÄ«, kad serverÄ« tika izpildÄ«ts pieprasÄ«jums, rakstÄ«ja gudri cilvēki auto_explain modulis. Tas ir pieejams gandrÄ«z visos visizplatÄ«tākajos PostgreSQL izplatÄ«jumos, un to var vienkārÅ”i aktivizēt konfigurācijas failā.

Ja tas saprot, ka kāds pieprasÄ«jums tiek izpildÄ«ts ilgāk par jÅ«su norādÄ«to ierobežojumu, tas notiek Ŕī pieprasÄ«juma plāna ā€œmomentuzņēmumuā€ un ieraksta tos kopā žurnālā.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Tagad it kā viss kārtÄ«bā, ejam uz baļķi un tur redzam... [teksts kāju lupatiņa]. Bet mēs par to nevaram pateikt neko citu, kā vien to, ka tas ir lielisks plāns, jo tā izpilde prasÄ«ja 11 ms.

Å Ä·iet, ka viss ir kārtÄ«bā, bet nekas nav skaidrs, kas patiesÄ«bā notika. Izņemot vispārējo laiku, mēs neko Ä«sti neredzam. Jo skatÄ«ties uz Ŕādu vienkārÅ”a teksta ā€œjēruā€ parasti nav vizuāli.

Bet pat tad, ja tas nav acīmredzams, pat ja tas ir neērti, pastāv daudz būtiskākas problēmas:

  • Mezgls norāda visa apakÅ”koka resursu summa zem viņa. Tas nozÄ«mē, ka jÅ«s nevarat vienkārÅ”i uzzināt, cik daudz laika tika pavadÄ«ts Å”ai konkrētajai indeksa skenÄ“Å”anai, ja zem tā ir kāds ligzdots stāvoklis. Mums ir dinamiski jāskatās, lai redzētu, vai iekŔā ir ā€œbērniā€ un nosacÄ«juma mainÄ«gie, CTE ā€“ un tas viss ā€œmÅ«su prātāā€ jāatņem.
  • Otrais punkts: uz mezgla norādÄ«tais laiks ir viena mezgla izpildes laiks. Ja Å”is mezgls tika izpildÄ«ts, piemēram, vairākas reizes veicot cilpu caur tabulas ierakstiem, tad plānā palielinās cilpu ā€” Ŕī mezgla ciklu ā€” skaits. Bet pats atomu izpildes laiks plāna ziņā paliek nemainÄ«gs. Tas ir, lai saprastu, cik ilgi Å”is mezgls tika veikts kopumā, jums ir jāreizina viena lieta ar otru - atkal "galvā".

Šādās situācijās saprotiet: "KurÅ” ir vājākais posms?" gandrÄ«z neiespējami. Tāpēc pat paÅ”i izstrādātāji to raksta ā€œrokasgrāmatāā€. "Izpratne par plānu ir māksla, kas jāapgÅ«st, jāpiedzÄ«vo...".

Taču mums ir 1000 izstrādātāju, un jÅ«s nevarat nodot Å”o pieredzi katram no viņiem. Es, tu, viņŔ zinu, bet kāds tur vairs nezina. VarbÅ«t viņŔ iemācÄ«sies, vai varbÅ«t ne, bet viņam tagad vajag strādāt - un kur viņŔ iegÅ«tu Å”o pieredzi?

Plāna vizualizācija

Tāpēc mēs sapratām, ka, lai tiktu galā ar Ŕīm problēmām, mums ir nepiecieÅ”ams laba plāna vizualizācija. [raksts]

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Vispirms mēs izgājām ā€œpa tirguā€ - paskatÄ«simies internetā, lai redzētu, kas vispār pastāv.

Bet izrādÄ«jās, ka ir ļoti maz salÄ«dzinoÅ”i ā€œdzÄ«vuā€ risinājumu, kas vairāk vai mazāk attÄ«stās - burtiski tikai viens: paskaidrojiet.depesz.com autors Huberts Lubačevskis. Ievadot plāna teksta attēlojumu laukā ā€œplÅ«smaā€, tiek parādÄ«ta tabula ar parsētajiem datiem:

  • paÅ”a mezgla apstrādes laiks
  • kopējais laiks visam apakÅ”kokam
  • statistiski paredzamo izgÅ«to ierakstu skaits
  • pats mezgla Ä·ermenis

Å im pakalpojumam ir arÄ« iespēja koplietot saiÅ”u arhÄ«vu. JÅ«s iemetāt tur savu plānu un teicāt: "Ei, Vasja, Å”eit ir saite, tur kaut kas nav kārtÄ«bā."

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Taču ir arī nelielas problēmas.

Pirmkārt, milzÄ«gs daudzums ā€œcopy-pasteā€. JÅ«s paņemat baļķa gabalu, iebāžat to tur, un atkal un atkal.

Otrkārt, nav nolasÄ«to datu apjoma analÄ«zes ā€” tie paÅ”i buferi, kas izvada EXPLAIN (ANALYZE, BUFFERS), mēs to Å”eit neredzam. ViņŔ vienkārÅ”i nezina, kā tos izjaukt, saprast un strādāt ar tiem. Kad lasāt daudz datu un saprotat, ka, iespējams, nepareizi sadalāt disku un atmiņas keÅ”atmiņu, Ŕī informācija ir ļoti svarÄ«ga.

TreÅ”ais negatÄ«vais punkts ir Ŕī projekta ļoti vājā attÄ«stÄ«ba. SaistÄ«bas ir ļoti mazas, ir labi, ja reizi seÅ”os mēneÅ”os, un kods ir Perl.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Bet tas viss ir ā€œdziesmu vārdiā€, mēs ar to varētu kaut kā sadzÄ«vot, taču ir viena lieta, kas mÅ«s ļoti atturēja no Ŕī pakalpojuma. Tās ir kļūdas kopējās tabulas izteiksmes (CTE) un dažādu dinamisku mezglu, piemēram, InitPlan/SubPlan, analÄ«zē.

Ja ticat Å”im attēlam, katra atseviŔķa mezgla kopējais izpildes laiks ir lielāks par visa pieprasÄ«juma kopējo izpildes laiku. Tas ir vienkārÅ”i - Ŕī CTE Ä£enerÄ“Å”anas laiks netika atņemts no CTE Scan mezgla. Tāpēc mēs vairs nezinām pareizo atbildi uz to, cik ilgi bija nepiecieÅ”ama pati CTE skenÄ“Å”ana.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Tad sapratām, ka laiks rakstÄ«t savējo - urā! Katrs izstrādātājs saka: "Tagad mēs rakstÄ«sim paÅ”i, tas bÅ«s ļoti vienkārÅ”i!"

Mēs izmantojām tīmekļa pakalpojumiem raksturīgu kaudzi: kodolu, kura pamatā ir Node.js + Express, izmantojām Bootstrap un D3.js, lai iegūtu skaistas diagrammas. Un mūsu cerības bija pilnībā pamatotas - pirmo prototipu saņēmām 2 nedēļu laikā:

  • pielāgota plāna parsētājs
    Tas ir, tagad mēs varam parsēt jebkuru plānu no tiem, ko ģenerēja PostgreSQL.
  • pareiza dinamisko mezglu analÄ«ze - CTE skenÄ“Å”ana, InitPlan, apakÅ”plāns
  • buferu sadalÄ«juma analÄ«ze - kur datu lapas tiek lasÄ«tas no atmiņas, kur no lokālās keÅ”atmiņas, kur no diska
  • ieguva skaidrÄ«bu
    Lai to visu ā€œneraktuā€ žurnālā, bet bildē uzreiz redzētu ā€œvājāko posmuā€.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Mums ir kaut kas lÄ«dzÄ«gs Å”im ar iekļautu sintakses izcelÅ”anu. Bet parasti mÅ«su izstrādātāji vairs nestrādā ar pilnÄ«gu plāna attēlojumu, bet gan ar Ä«sāku. Galu galā mēs jau esam parsējuÅ”i visus skaitļus un izmetuÅ”i tos pa kreisi un pa labi, un pa vidu atstājām tikai pirmo rindiņu, kas tas par mezglu: CTE Scan, CTE paaudze vai Seq Scan pēc kādas zÄ«mes.

Šis ir saīsinātais attēlojums, ko mēs saucam plāna veidne.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Kas vēl bÅ«tu ērti? BÅ«tu ērti redzēt, kāda daļa no mÅ«su kopējā laika ir atvēlēta kuram mezglam - un vienkārÅ”i "pielikt" malā sektoru diagramma.

Rādām uz mezglu un redzam ā€“ izrādās, ka Seq Scan aizņēma mazāk par ceturtdaļu no kopējā laika, bet atlikuŔās 3/4 paņēma CTE Scan. Å ausmas! Å Ä« ir neliela piezÄ«me par CTE Scan ā€œuguns ātrumuā€, ja jÅ«s tos aktÄ«vi izmantojat savos vaicājumos. Tie nav Ä«paÅ”i ātri - tie ir zemāki pat par parasto tabulu skenÄ“Å”anu. [raksts] [raksts]

Bet parasti Ŕādas diagrammas ir interesantākas, sarežģītākas, kad mēs uzreiz norādām uz segmentu un redzam, piemēram, ka vairāk nekā pusi no laika kāds Seq Scan ā€œapēdaā€. Turklāt iekŔā bija kaut kāds Filtrs, pēc tā tika izmesti daudz ierakstu... Vari tieÅ”i Å”o bildi iemest izstrādātājam un teikt: ā€œVasja, tev te viss ir slikti! Izdomā, paskaties ā€“ kaut kas nav kārtÄ«bā!ā€

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Protams, bija iesaistÄ«ti daži ā€œgrābekļiā€.

Pirmā lieta, ko mēs saskārāmies, bija noapaļoÅ”anas problēma. Katra atseviŔķa mezgla laiks plānā ir norādÄ«ts ar precizitāti 1 Ī¼s. Un, kad mezglu ciklu skaits pārsniedz, piemēram, 1000 - pēc izpildes PostgreSQL dalÄ«ts "precizitātes robežās", tad, aprēķinot atpakaļ, mēs iegÅ«stam kopējo laiku "kaut kur starp 0.95 ms un 1.05 ms". Ja skaitÄ«Å”ana pāriet uz mikrosekundēm, tas ir labi, bet, kad tas jau ir [miljoni]sekundes, Ŕī informācija ir jāņem vērā, ā€œatsaistotā€ resursus no plāna ā€œkurÅ” cik patērējaā€ mezgliem.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Otrs, sarežģītāks punkts ir resursu (Å”o buferu) sadale starp dinamiskajiem mezgliem. Tas mums izmaksāja pirmās 2 prototipa nedēļas un vēl 4 nedēļas.

Ir diezgan viegli iegÅ«t Ŕāda veida problēmu ā€” mēs veicam CTE un it kā kaut ko tajā lasām. Faktiski PostgreSQL ir ā€œgudrsā€ un tur neko tieÅ”i nelasÄ«s. Tad mēs no tā ņemam pirmo ierakstu un simts pirmo ierakstu no tā paÅ”a CTE.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Mēs skatāmies uz plānu un saprotam - tas ir dÄ«vaini, mums ir ā€œpatērētiā€ 3 buferi (datu lapas) Seq Scan, vēl 1 CTE Scan un vēl 2 otrajā CTE Scan. Tas ir, ja mēs vienkārÅ”i visu summējam, mēs iegÅ«sim 6, bet no planÅ”etdatora mēs nolasām tikai 3! CTE Scan neko nelasa no jebkuras vietas, bet darbojas tieÅ”i ar procesa atmiņu. RespektÄ«vi, Å”eit kaut kas nepārprotami nav kārtÄ«bā!

PatiesÄ«bā izrādās, ka Å”eit ir visas tās 3 datu lapas, kas tika pieprasÄ«tas no Seq Scan, vispirms 1 prasÄ«ja 1. CTE Scan, un tad 2. un vēl 2 viņam tika nolasÄ«tas.Tas ir, kopā Dati tika nolasÄ«ti 3 lappusēs, nevis 6.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Un Ŕī bilde lika mums saprast, ka plāna izpilde vairs nav koks, bet vienkārÅ”i kaut kāds aciklisks grafiks. Un mēs saņēmām Ŕādu diagrammu, lai mēs saprastu, ā€œkas vispirms ir no kurienes nācaā€. Tas ir, Å”eit mēs izveidojām CTE no pg_class un lÅ«dzām to divreiz, un gandrÄ«z viss mÅ«su laiks tika pavadÄ«ts filiālē, kad mēs to lÅ«dzām otro reizi. Skaidrs, ka 2. ieraksta lasÄ«Å”ana ir daudz dārgāka nekā tikai 101. ieraksta lasÄ«Å”ana no planÅ”etdatora.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Kādu brÄ«di izelpojām. Viņi teica: ā€œTagad, Neo, tu zini kung fu! Tagad mÅ«su pieredze ir tieÅ”i jÅ«su ekrānā. Tagad jÅ«s varat to izmantot." [raksts]

Baļķu konsolidācija

MÅ«su 1000 izstrādātāju atviegloti nopÅ«tās. Bet mēs sapratām, ka mums ir tikai simtiem ā€œkaujasā€ serveru, un visa Ŕī izstrādātāju ā€œkopÄ“Å”ana-ielÄ«mÄ“Å”anaā€ nepavisam nav ērta. Sapratām, ka jāsavāc paÅ”iem.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Kopumā ir standarta modulis, kas var apkopot statistiku, tomēr tas ir jāaktivizē arÄ« konfigurācijā - tas modulis pg_stat_statements. Bet viņŔ mums nederēja.

Pirmkārt, tas pieŔķir vieniem un tiem paÅ”iem vaicājumiem, izmantojot dažādas shēmas vienā datu bāzē dažādi vaicājuma ID. Tas ir, ja jÅ«s vispirms to darāt SET search_path = '01'; SELECT * FROM user LIMIT 1;un tad SET search_path = '02'; un tas pats pieprasÄ«jums, tad Ŕī moduļa statistikai bÅ«s dažādi ieraksti, un es nevarÄ“Å”u savākt vispārÄ«gu statistiku tieÅ”i Ŕī pieprasÄ«juma profila kontekstā, neņemot vērā shēmas.

Otrs punkts, kas neļāva mums to izmantot, ir plānu trÅ«kums. Tas ir, plāna nav, ir tikai pats pieprasÄ«jums. Mēs redzam, kas palēninājās, bet nesaprotam, kāpēc. Un Å”eit mēs atgriežamies pie strauji mainÄ«gas datu kopas problēmas.

Un pēdējais brÄ«dis - "faktu" trÅ«kums. Tas ir, jÅ«s nevarat risināt konkrētu vaicājuma izpildes gadÄ«jumu ā€” tāda nav, ir tikai apkopota statistika. Lai gan ar to ir iespējams strādāt, tas ir vienkārÅ”i ļoti grÅ«ti.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Tāpēc nolēmām cīnīties ar copy-paste un sākām rakstīt kolektors.

Kolektors izveido savienojumu, izmantojot SSH, izveido droÅ”u savienojumu ar serveri ar datu bāzi, izmantojot sertifikātu, un tail -F ā€œpieÄ·erasā€ tam žurnāla failā. Tātad Å”ajā sesijā mēs iegÅ«stam pilnÄ«gu visa žurnālfaila "spoguli"., ko serveris Ä£enerē. PaÅ”a servera slodze ir minimāla, jo mēs tur neko neparsējam, mēs tikai atspoguļojam trafiku.

Tā kā interfeisu jau bijām sākuÅ”i rakstÄ«t Node.js, turpinājām tajā rakstÄ«t savācēju. Un Ŕī tehnoloÄ£ija sevi ir attaisnojusi, jo ir ļoti ērti izmantot JavaScript, lai strādātu ar vāji formatētiem teksta datiem, kas ir žurnāls. Un pati Node.js infrastruktÅ«ra kā aizmugures platforma ļauj viegli un ērti strādāt ar tÄ«kla savienojumiem un, protams, ar jebkādām datu plÅ«smām.

AttiecÄ«gi mēs ā€œizstiepjamā€ divus savienojumus: pirmo, lai ā€œklausÄ«tosā€ paŔā žurnālā un ņemtu to sev, un otro, lai periodiski jautātu bāzei. ā€œBet žurnālā redzams, ka zÄ«me ar 123. ID ir bloķētaā€, taču izstrādātājam tas neko nenozÄ«mē, un bÅ«tu jauki pajautāt datubāzei: ā€œKas tik un tā ir OID = 123?ā€ Tāpēc mēs periodiski jautājam bāzei to, ko vēl nezinām par sevi.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

"Ir tikai viena lieta, ko jÅ«s neņēmāt vērā, ir ziloņiem lÄ«dzÄ«gu biÅ”u suga!..." Mēs sākām izstrādāt Å”o sistēmu, kad vēlējāmies uzraudzÄ«t 10 serverus. MÅ«su izpratnē viskritiskākais, kur radās dažas problēmas, ar kurām bija grÅ«ti tikt galā. Bet pirmajā ceturksnÄ« par monitoringu saņēmām simtu - jo sistēma darbojās, visi to gribēja, visiem bija ērti.

Tas viss ir jāsaskaita, datu plÅ«sma ir liela un aktÄ«va. PatiesÄ«bā tas, ko mēs uzraugām, ar ko varam tikt galā, ir tas, ko mēs izmantojam. Mēs arÄ« izmantojam PostgreSQL kā datu krātuvi. Un nekas nevar ātrāk ā€œielietā€ datus par operatoru COPY Vēl nē.

Bet vienkārÅ”i datu ā€œielieÅ”anaā€ patiesÄ«bā nav mÅ«su tehnoloÄ£ija. Jo, ja jums ir aptuveni 50 100 pieprasÄ«jumu sekundē uz simts serveriem, tas Ä£enerēs 150ā€“XNUMX GB žurnālu dienā. Tāpēc mums bija rÅ«pÄ«gi ā€œjānogriežā€ pamatne.

Pirmkārt, mēs to izdarÄ«jām sadalÄ«Å”ana pa dienām, jo pa lielam nevienu neinteresē korelācija starp dienām. Kāda nozÄ«me ir tam, kas jums bija vakar, ja Å”ovakar jÅ«s izlaidāt jaunu lietojumprogrammas versiju un jau jaunu statistiku.

Otrkārt, mēs mācÄ«jāmies (bijām spiesti) ļoti, ļoti ātri rakstÄ«t, izmantojot COPY. Tas ir, ne tikai COPYjo viņŔ ir ātrāks par INSERT, un vēl ātrāk.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

TreÅ”ais punkts ā€“ vajadzēja attiecÄ«gi atteikties no trigeriem un ārējām atslēgām. Tas ir, mums vispār nav atsauces integritātes. Jo, ja jums ir tabula, kurā ir pāris FK, un jÅ«s datu bāzes struktÅ«rā sakāt, ka "Å”eit ir žurnāla ieraksts, uz kuru FK atsaucas, piemēram, uz ierakstu grupu", tad, ievietojot to, PostgreSQL nekas cits neatliek, kā to ņemt un darÄ«t godÄ«gi SELECT 1 FROM master_fk1_table WHERE ... ar identifikatoru, kuru mēģināt ievietot - tikai, lai pārbaudÄ«tu, vai Å”is ieraksts tur ir, vai jÅ«s ar ievietoÅ”anu nenojaucat Å”o ārējo atslēgu.

Viena ieraksta vietā mērķa tabulai un tās indeksiem mēs gūstam papildu labumu, lasot visas tabulas, uz kurām tā attiecas. Bet mums tas nemaz nav vajadzīgs - mūsu uzdevums ir ierakstīt pēc iespējas vairāk un pēc iespējas ātrāk ar mazāko slodzi. Tātad FK - uz leju!

Nākamais punkts ir apkopoÅ”ana un jaukÅ”ana. Sākotnēji mēs tos ieviesām datu bāzē - galu galā ir ērti uzreiz, kad pienāk ieraksts, to izdarÄ«t kaut kādā planÅ”etdatorā "plus viens" tieÅ”i trigerÄ«. Nu, tas ir ērti, bet tas pats slikts - jÅ«s ievietojat vienu ierakstu, bet esat spiests lasÄ«t un rakstÄ«t kaut ko citu no citas tabulas. Turklāt jÅ«s ne tikai lasāt un rakstāt, bet arÄ« darāt to katru reizi.

Tagad iedomājieties, ka jums ir tabula, kurā jÅ«s vienkārÅ”i saskaitāt pieprasÄ«jumu skaitu, kas ir nosÅ«tÄ«ti caur noteiktu resursdatoru: +1, +1, +1, ..., +1. Un jums principā tas nav vajadzÄ«gs - tas viss ir iespējams summa atmiņā uz kolekcionāra un nosÅ«tiet uz datu bāzi vienā piegājienā +10.

Jā, dažu problēmu gadÄ«jumā jÅ«su loÄ£iskā integritāte var ā€œizjuktā€, bet tas ir gandrÄ«z nereāls gadÄ«jums - jo jums ir parasts serveris, tam ir akumulators kontrollerÄ«, jums ir darÄ«jumu žurnāls, žurnāls failu sistēma... Kopumā nav tā vērts. Produktivitātes zudums, ko iegÅ«stat, darbinot trigerus/FK, nav to izdevumu vērts, kas jums rodas.

Tāpat ir ar jaukÅ”anu. Pie jums atlido noteikts pieprasÄ«jums, jÅ«s no tā datu bāzē izskaitļojat noteiktu identifikatoru, ierakstāt to datu bāzē un pēc tam pastāstāt visiem. Viss ir kārtÄ«bā, lÄ«dz ierakstÄ«Å”anas laikā pie jums pienāk otra persona, kas vēlas ierakstÄ«t to paÅ”u - un jÅ«s tiekat bloķēts, un tas jau ir slikti. Tāpēc, ja dažu ID Ä£enerÄ“Å”anu varat pārsÅ«tÄ«t klientam (attiecÄ«bā pret datu bāzi), labāk to darÄ«t.

Mums bija vienkārÅ”i ideāli izmantot MD5 no teksta - pieprasÄ«jums, plāns, veidne,... Mēs to aprēķinām savācēja pusē, un gatavo ID ā€œieberamā€ datu bāzē. MD5 garums un ikdienas sadalÄ«Å”ana ļauj mums neuztraukties par iespējamām sadursmēm.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Bet, lai to visu ātri ierakstītu, mums bija jāmaina pati ierakstīŔanas procedūra.

Kā jÅ«s parasti rakstāt datus? Mums ir kaut kāda datu kopa, mēs to sadalām vairākās tabulās, un tad KOPĒJAM - vispirms pirmajā, tad otrajā, treÅ”ajā... Tas ir neērti, jo Ŕķiet, ka mēs rakstām vienu datu straumi trÄ«s soļos. secÄ«gi. NepatÄ«kami. Vai to var izdarÄ«t ātrāk? Var!

Lai to izdarÄ«tu, pietiek tikai sadalÄ«t Ŕīs plÅ«smas paralēli viena otrai. Izrādās, ka mums ir kļūdas, pieprasÄ«jumi, veidnes, bloÄ·Ä“Å”ana, ... lido atseviŔķos pavedienos - un mēs to visu rakstām paralēli. Pietiekami Å”im pastāvÄ«gi atvērt COPY kanālu katrai atseviŔķai mērÄ·a tabulai.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Tas ir, pie kolekcionāra vienmēr ir straume, kurā varu ierakstÄ«t sev nepiecieÅ”amos datus. Bet, lai datu bāze redzētu Å”os datus un kāds neiestrēgtu, gaidot, kad Å”ie dati tiks ierakstÄ«ti, COPY ir jāpārtrauc noteiktos intervālos. Mums visefektÄ«vākais periods bija apmēram 100ms - aizveram un uzreiz atkal atveram pie tā paÅ”a galda. Un, ja mums nav pietiekami daudz vienas plÅ«smas dažu maksimumu laikā, mēs veicam apvienoÅ”anu lÄ«dz noteiktai robežai.

Turklāt mēs noskaidrojām, ka Ŕādam slodzes profilam jebkura apkopoÅ”ana, kad ieraksti tiek vākti pa partijām, ir ļauni. Klasiskais ļaunums ir INSERT ... VALUES un vēl 1000 ierakstu. Jo tajā brÄ«dÄ« jums ir rakstÄ«Å”anas maksimums datu nesējā, un visi pārējie, kas mēģinās kaut ko ierakstÄ«t diskā, gaidÄ«s.

Lai atbrÄ«votos no Ŕādām anomālijām, vienkārÅ”i neko neapkopojiet, nebuferējiet vispār. Un, ja notiek buferizācija uz diska (par laimi, Stream API Node.js ļauj to uzzināt) - atlikt Å”o savienojumu. Kad saņemat pasākumu, ka tas atkal ir bezmaksas, rakstiet uz to no uzkrātās rindas. Un, kamēr tas ir aizņemts, paņemiet nākamo brÄ«vo no baseina un uzrakstiet tam.

Pirms Ŕīs pieejas ievieÅ”anas datu ierakstÄ«Å”anai mums bija aptuveni 4K rakstÄ«Å”anas darbÄ«bas, un tādā veidā mēs samazinājām slodzi 4 reizes. Tagad tās ir auguÅ”as vēl 6 reizes, pateicoties jaunām uzraudzÄ«tām datubāzēm ā€“ lÄ«dz 100MB/s. Un tagad mēs glabājam žurnālus pēdējos 3 mēneÅ”us apmēram 10-15 TB apjomā, cerot, ka tikai trÄ«s mēneÅ”u laikā jebkurÅ” izstrādātājs spēs atrisināt jebkuru problēmu.

Mēs saprotam problēmas

Bet vienkārÅ”i savākt visus Å”os datus ir labi, noderÄ«gi, atbilstoÅ”i, bet nepietiek ā€“ tas ir jāsaprot. Jo tie ir miljoniem dažādu plānu dienā.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Bet miljoni ir nepārvaldāmi, vispirms ir jādara ā€œmazākā€. Un, pirmkārt, jums ir jāizlemj, kā jÅ«s organizēsit Å”o ā€œmazākoā€ lietu.

Mēs esam identificējuÅ”i trÄ«s galvenos punktus:

  • kurÅ” nosÅ«tÄ«ja Å”o pieprasÄ«jumu
    Tas ir, no kuras lietojumprogrammas tas ā€œnonācaā€: tÄ«mekļa saskarne, aizmugursistēma, maksājumu sistēma vai kaut kas cits.
  • kur tas notika
    Uz kāda konkrēta servera? Jo, ja jums ir vairāki serveri zem vienas aplikācijas, un pēkŔņi viens "stulbst" (jo "disks ir sapuvis", "atmiņa noplÅ«da", kāda cita problēma), tad jums ir Ä«paÅ”i jāvērÅ”as pie servera.
  • kā problēma tā vai citādi izpaudās

Lai saprastu, "kas" mums nosÅ«tÄ«ja pieprasÄ«jumu, mēs izmantojam standarta rÄ«ku - sesijas mainÄ«gā iestatÄ«Å”anu: SET application_name = '{bl-host}:{bl-method}'; ā€” mēs nosÅ«tām tā biznesa loÄ£ikas resursdatora nosaukumu, no kura tiek saņemts pieprasÄ«jums, un tās metodes vai lietojumprogrammas nosaukumu, kas to ierosināja.

Kad esam nodevuÅ”i pieprasÄ«juma ā€œÄ«paÅ”niekuā€, tas ir jāizvada žurnālā - Å”im nolÅ«kam mēs konfigurējam mainÄ«go log_line_prefix = ' %m [%p:%v] [%d] %r %a'. Interesentiem, varbÅ«t paskaties rokasgrāmatāko tas viss nozÄ«mē. Izrādās, ka mēs žurnālā redzam:

  • laiks
  • procesu un darÄ«jumu identifikatori
  • datu bāzes nosaukums
  • Tās personas IP, kura nosÅ«tÄ«ja Å”o pieprasÄ«jumu
  • un metodes nosaukums

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Tad sapratām, ka nav īpaŔi interesanti skatīties korelāciju vienam pieprasījumam starp dažādiem serveriem. Nereti gadās, ka viena lietojumprogramma Ŕur un tur vienādi sabojājas. Bet pat tad, ja tas ir vienāds, apskatiet kādu no Ŕiem serveriem.

Tātad, lūk, griezums "viens serveris - viena diena" mums ar to pietika jebkurai analīzei.

Pirmā analÄ«tiskā sadaļa ir tāda pati "paraugs" - plāna saÄ«sināta prezentācijas forma, attÄ«rÄ«ta no visiem skaitliskiem rādÄ«tājiem. Otrais griezums ir lietojumprogramma vai metode, bet treÅ”ais ir konkrētais plāna mezgls, kas mums radÄ«ja problēmas.

Pārejot no konkrētiem gadÄ«jumiem uz veidnēm, mēs ieguvām uzreiz divas priekÅ”rocÄ«bas:

  • daudzkārtēja analÄ«zes objektu skaita samazināŔana
    Mums problēma vairs nav jāanalizē pēc tÅ«kstoÅ”iem vaicājumu vai plānu, bet pēc desmitiem veidņu.
  • laika skala
    Tas ir, apkopojot ā€œfaktusā€ noteiktā sadaļā, jÅ«s varat parādÄ«t to izskatu dienas laikā. Un te var saprast, ka, ja tev ir kaut kāds modelis, kas notiek, piemēram, reizi stundā, bet tam vajadzētu notikt reizi dienā, ir jāpadomā, kas nogāja greizi - kas to izraisÄ«ja un kāpēc, varbÅ«t tam vajadzētu bÅ«t Å”eit nevajadzētu. Å Ä« ir vēl viena neskaitliska, tÄ«ri vizuāla analÄ«zes metode.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Pārējās metodes ir balstÄ«tas uz rādÄ«tājiem, kurus mēs iegÅ«stam no plāna: cik reizes Ŕāds modelis notika, kopējais un vidējais laiks, cik daudz datu tika nolasÄ«ts no diska un cik no atmiņas...

Tā kā, piemēram, jÅ«s nonākat resursdatora analÄ«tikas lapā, paskatieties - diskā kaut kas sāk lasÄ«t pārāk daudz. ServerÄ« esoÅ”ais disks to nevar apstrādāt ā€“ kurÅ” no tā lasa?

Un jÅ«s varat kārtot pēc jebkuras kolonnas un izlemt, ar ko jÅ«s tagad nodarbosities - procesora vai diska slodze, vai kopējais pieprasÄ«jumu skaits... Mēs to sakārtojām, apskatÄ«jām ā€œaugŔākosā€, labojām un izlaida jaunu lietojumprogrammas versiju.
[videolekcija]

Un uzreiz jÅ«s varat redzēt dažādas lietojumprogrammas, kurām ir viena un tā pati veidne no pieprasÄ«juma, piemēram, SELECT * FROM users WHERE login = 'Vasya'. PriekÅ”gals, aizmugursistēma, apstrāde... Un jÅ«s domājat, kāpēc apstrāde nolasa lietotāju, ja viņŔ ar viņu nesazinās.

Pretējs veids ir uzreiz redzēt no lietojumprogrammas, ko tā dara. Piemēram, frontend ir tas, tas, Å”is un tas reizi stundā (laika skala palÄ«dz). Un uzreiz rodas jautājums: Ŕķiet, ka nav frontend uzdevums reizi stundā kaut ko darÄ«t...

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Pēc kāda laika mēs sapratām, ka mums trÅ«kst apkopojuma statistika pēc plāna mezgliem. No plāniem izolējām tikai tos mezglus, kas kaut ko dara ar paÅ”u tabulu datiem (lasa/raksta tos pēc indeksa vai ne). Faktiski salÄ«dzinājumā ar iepriekŔējo attēlu tiek pievienots tikai viens aspekts - cik ierakstus Å”is mezgls mums atnesa?, un cik tika atmesti (Filtra noņemtās rindas).

Jums nav piemērota indeksa uz plāksnÄ«tes, jÅ«s tai iesniedzat pieprasÄ«jumu, tas lido garām indeksam, iekrÄ«t Seq Scan... jÅ«s esat izfiltrējis visus ierakstus, izņemot vienu. Kāpēc jums ir nepiecieÅ”ami 100 miljoni filtrētu ierakstu dienā? Vai nav labāk apkopot indeksu?

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Izanalizējot visus plānus pēc mezgla, mēs sapratām, ka plānos ir dažas tipiskas struktÅ«ras, kas, visticamāk, izskatās aizdomÄ«gas. Un bÅ«tu jauki pateikt izstrādātājam: ā€œDraugs, Å”eit jÅ«s vispirms izlasiet pēc indeksa, pēc tam kārtojat un pēc tam nogriežatā€ - parasti ir viens ieraksts.

Ikviens, kurÅ” rakstÄ«jis vaicājumus, droÅ”i vien ir saskāries ar Ŕādu modeli: ā€œIedodiet man pēdējo Vasjas pasÅ«tÄ«jumu, tā datumu.ā€ Un, ja jums nav datu indeksa vai izmantotajā rādÄ«tājā nav datuma, tad jÅ«s uzkāp tieÅ”i uz tā paÅ”a ā€œgrābekļaā€ .

Bet mēs zinām, ka tas ir "grābeklis" - kāpēc gan nekavējoties nepaziņot izstrādātājam, kas viņam jādara. AttiecÄ«gi, tagad atverot plānu, mÅ«su izstrādātājs uzreiz redz skaistu bildi ar padomiem, kur uzreiz viņam saka: ā€œTev ir problēmas Å”ur tur, bet tās tiek risinātas tā un tā.ā€

LÄ«dz ar to pieredzes apjoms, kas bija nepiecieÅ”ams problēmu risināŔanai sākumā un tagad, ir ievērojami samazinājies. Tāds rÄ«ks mums ir.

PostgreSQL vaicājumu lielapjoma optimizācija. Kirils Borovikovs (Tensors)

Avots: www.habr.com

Pievieno komentāru