Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB

Onlangs het ek jou vertel hoe, met behulp van standaard resepte verhoog die werkverrigting van SQL-leesnavrae vanaf die PostgreSQL-databasis. Vandag sal ons praat oor hoe opname kan meer doeltreffend gedoen word in die databasis sonder om enige "draaie" in die konfigurasie te gebruik - bloot deur die datavloei korrek te organiseer.

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB

#1. Seksie

'n Artikel oor hoe en hoekom dit die moeite werd is om te organiseer toegepaste partisie "in teorie" reeds was, hier sal ons praat oor die praktyk van die toepassing van sommige benaderings binne ons moniteringsdiens vir honderde PostgreSQL-bedieners.

"Dinge van vervloë dae ..."

Aanvanklik, soos enige MVP, het ons projek onder 'n redelik ligte las begin - monitering is slegs vir 'n dosyn van die mees kritieke bedieners uitgevoer, alle tafels was relatief kompak ... Maar soos die tyd aangegaan het, het die aantal gemonitorde gashere meer geword en meer, en weereens het ons probeer om iets met een van te doen tafels 1.5TB groot, het ons besef dat alhoewel dit moontlik was om so voort te leef, dit baie ongerieflik was.

Die tye was amper soos epiese tye, verskillende weergawes van PostgreSQL 9.x was relevant, so alle partisionering moes "handmatig" gedoen word - deur tabel oorerwing en snellers roetering met dinamiese EXECUTE.

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB
Die gevolglike oplossing blyk universeel genoeg te wees dat dit na alle tabelle vertaal kon word:

  • 'n Leë "header" ouertabel is verklaar, wat alles beskryf het nodige indekse en snellers.
  • Die rekord uit die kliënt se oogpunt is in die “wortel”-tabel gemaak, en intern deur gebruik te maak roetesneller BEFORE INSERT die rekord is "fisies" in die vereiste afdeling ingevoeg. As daar nog nie so iets was nie, het ons 'n uitsondering gekry en...
  • … deur die gebruik van CREATE TABLE ... (LIKE ... INCLUDING ...) is geskep op grond van die sjabloon van die ouertabel afdeling met 'n beperking op die verlangde datumsodat wanneer data herwin word, lees slegs daarin uitgevoer word.

PG10: eerste poging

Maar partisie deur oorerwing was histories nie goed geskik vir die hantering van 'n aktiewe skryfstroom of 'n groot aantal kinderpartisies nie. Byvoorbeeld, jy kan onthou dat die algoritme vir die keuse van die vereiste afdeling gehad het kwadratiese kompleksiteit, dat dit met 100+ afdelings werk, verstaan ​​jy self hoe...

In PG10 is hierdie situasie grootliks geoptimaliseer deur ondersteuning te implementeer inheemse verdeling. Daarom het ons dit dadelik probeer toepas nadat ons die berging migreer het, maar ...

Soos dit geblyk het nadat jy deur die handleiding gegrawe het, is die oorspronklik verdeelde tabel in hierdie weergawe:

  • ondersteun nie indeksbeskrywings nie
  • ondersteun nie snellers daarop nie
  • kan niemand se "afstammeling" wees nie
  • ondersteun nie INSERT ... ON CONFLICT
  • kan nie 'n afdeling outomaties genereer nie

Nadat ons 'n pynlike hou op die voorkop met 'n hark gekry het, het ons besef dat dit onmoontlik sou wees sonder om die aansoek te wysig, en het verdere navorsing vir ses maande uitgestel.

PG10: tweede kans

So, ons het begin om die probleme wat ontstaan ​​het een vir een op te los:

  1. Omdat snellers en ON CONFLICT Ons het gevind dat ons hulle nog hier en daar nodig het, so ons het 'n tussenstadium gemaak om dit uit te werk proxy tabel.
  2. Ontslae geraak van "routing" in snellers - dit wil sê van EXECUTE.
  3. Hulle het dit apart uitgehaal sjabloon tabel met alle indeksesodat hulle nie eers in die volmagtabel teenwoordig is nie.

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB
Uiteindelik, na dit alles, het ons die hooftabel inheems verdeel. Die skep van 'n nuwe afdeling word steeds aan die aansoek se gewete oorgelaat.

"Saag" woordeboeke

Soos in enige analitiese stelsel, het ons ook "feite" en "snitte" (woordeboeke). In ons geval het hulle in hierdie hoedanigheid opgetree bv. sjabloon liggaam soortgelyke stadige navrae of die teks van die navraag self.

“Feite” is al vir 'n lang tyd per dag opgedeel, so ons het rustig verouderde afdelings uitgevee, en dit het ons nie gepla nie (logs!). Maar daar was 'n probleem met woordeboeke...

Nie om te sê dat daar baie van hulle was nie, maar ongeveer 100 TB se "feite" het gelei tot 'n 2.5 TB woordeboek. Jy kan niks gerieflik uit so 'n tabel uitvee nie, jy kan dit nie betyds saamdruk nie, en skryf daarna het geleidelik stadiger geword.

Soos 'n woordeboek... daarin moet elke inskrywing presies een keer aangebied word... en dit is korrek, maar!.. Niemand keer ons om te hê 'n aparte woordeboek vir elke dag! Ja, dit bring 'n sekere oortolligheid mee, maar dit laat toe:

  • skryf/lees vinniger as gevolg van kleiner seksie grootte
  • verbruik minder geheue deur met meer kompakte indekse te werk
  • stoor minder data as gevolg van die vermoë om verouderde vinnig te verwyder

As gevolg van die hele kompleks van maatreëls SVE-lading het met ~30% afgeneem, skyflading met ~50%:

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB
Terselfdertyd het ons voortgegaan om presies dieselfde ding in die databasis te skryf, net met minder vrag.

#2. Databasis evolusie en herfaktorering

So ons het gevestig op wat ons het elke dag het sy eie afdeling met data. Eintlik, CHECK (dt = '2018-10-12'::date) - en daar is 'n partisiesleutel en die voorwaarde vir 'n rekord om in 'n spesifieke afdeling te val.

Aangesien alle verslae in ons diens in die konteks van 'n spesifieke datum gebou is, was die indekse vir hulle sedert "nie-gepartisioneerde tye" alle tipes (Bediener, Datum, Plan Sjabloon), (Bediener, Datum, Plan node), (Datum, Foutklas, Bediener), ...

Maar nou woon hulle op elke afdeling jou kopieë elke so 'n indeks... En binne elke afdeling datum is 'n konstante... Dit blyk dat ons nou in elke so 'n indeks is voer eenvoudig 'n konstante in as een van die velde, wat beide sy volume en die soektyd daarvoor verhoog, maar geen resultaat bring nie. Hulle het die hark vir hulself oorgelaat, oops...

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB
Die rigting van optimalisering is voor die hand liggend - eenvoudig verwyder die datumveld uit alle indekse op gepartisioneerde tafels. Gegewe ons volumes, is die wins omtrent 1 TB/week!

Kom ons let nou daarop dat hierdie teragreep nog op een of ander manier aangeteken moes word. Dit wil sê, ons ook die skyf behoort nou minder te laai! Hierdie foto toon duidelik die effek wat verkry is van die skoonmaak, waaraan ons 'n week gewy het:

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB

#3. “Verspreiding” van die pieklading

Een van die groot probleme van gelaaide stelsels is oortollige sinchronisasie sommige operasies wat dit nie vereis nie. Soms “omdat hulle nie agtergekom het nie”, soms “was dit makliker so”, maar vroeër of later moet jy daarvan ontslae raak.

Kom ons zoom in op die vorige prent en sien dat ons 'n skyf het “pomp” onder die las met dubbele amplitude tussen aangrensende steekproewe, wat duidelik "statisties" nie met so 'n aantal operasies behoort te gebeur nie:

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB

Dit is redelik maklik om te bereik. Ons het reeds begin monitor byna 1000 bedieners, elkeen word verwerk deur 'n aparte logiese draad, en elke draad herstel die opgehoopte inligting wat na die databasis gestuur moet word op 'n sekere frekwensie, iets soos hierdie:

setInterval(sendToDB, interval)

Die probleem hier lê juis in die feit dat alle drade begin op ongeveer dieselfde tyd, so hul stuurtye val byna altyd "tot die punt" saam. Oeps #2...

Gelukkig is dit redelik maklik om reg te stel, 'n "lukraak" aanloop by te voeg volgens tyd:

setInterval(sendToDB, interval * (1 + 0.1 * (Math.random() - 0.5)))

#4. Ons kas wat ons nodig het

Die derde tradisionele hoëladingsprobleem is geen kas nie waar hy is kon wees.

Ons het dit byvoorbeeld moontlik gemaak om in terme van plannodusse (al hierdie Seq Scan on users), maar dink dadelik dat hulle grotendeels dieselfde is - hulle het vergeet.

Nee, natuurlik word niks weer na die databasis geskryf nie, dit sny die sneller af met INSERT ... ON CONFLICT DO NOTHING. Maar hierdie data bereik steeds die databasis, en dit is onnodig lees om te kyk vir konflik moet doen. Oeps #3...

Die verskil in die aantal rekords wat na die databasis gestuur word voor/nadat kas geaktiveer is, is duidelik:

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB

En dit is die gepaardgaande afname in stoorlading:

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB

In totaal

"Terabyte-per-dag" klink net skrikwekkend. As jy alles reg doen, dan is dit net 2^40 grepe / 86400 sekondes = ~12.5MB/sdat selfs lessenaar IDE skroewe gehou. 🙂

Maar ernstig, selfs met 'n tienvoudige "skeef" van die vrag gedurende die dag, kan jy maklik aan die vermoëns van moderne SSD's voldoen.

Ons skryf in PostgreSQL op sublight: 1 gasheer, 1 dag, 1TB

Bron: will.com

Voeg 'n opmerking