Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB

Nedavno sam vam rekao kako, koristeći standardne recepte povećati izvedbu SQL upita za čitanje iz PostgreSQL baze podataka. Danas ćemo govoriti o tome kako snimanje može biti učinkovitije u bazi podataka bez korištenja ikakvih "zaokreta" u konfiguraciji - jednostavnim ispravnim organiziranjem protoka podataka.

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB

#1. Sekcioniranje

Članak o tome kako i zašto se isplati organizirati primijenjena particija "u teoriji" već bilo, ovdje ćemo govoriti o praksi primjene nekih pristupa unutar naše usluga nadzora za stotine PostgreSQL poslužitelja.

"Stvari prošlih dana..."

U početku, kao i svaki MVP, naš je projekt započeo pod relativno malim opterećenjem - nadgledanje se provodilo samo za deset najkritičnijih poslužitelja, sve su tablice bile relativno kompaktne... Ali kako je vrijeme prolazilo, broj nadziranih hostova postajao je sve veći. , i još jednom smo pokušali nešto učiniti s jednim od tablice veličine 1.5TB, shvatili smo da iako je moguće nastaviti ovako živjeti, bilo je vrlo nezgodno.

Vremena su bila gotovo kao epska vremena, različite verzije PostgreSQL 9.x bile su relevantne, tako da su sva particioniranja morala biti napravljena "ručno" - kroz nasljeđivanje tablice i okidači usmjeravanje s dinamičkim EXECUTE.

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB
Pokazalo se da je dobiveno rješenje dovoljno univerzalno da se može prevesti na sve tablice:

  • Deklarirana je prazna roditeljska tablica "zaglavlja", koja je sve opisala potrebne indekse i okidače.
  • Zapis sa stajališta klijenta napravljen je u “root” tablici, te interno korištenjem okidač za usmjeravanje BEFORE INSERT zapis je "fizički" umetnut u traženi odjeljak. Ako toga još nije bilo, uhvatili smo iznimku i...
  • … pomoću CREATE TABLE ... (LIKE ... INCLUDING ...) je kreiran na temelju predloška nadređene tablice odjeljak s ograničenjem željenog datumatako da se kod dohvaćanja podataka čitanje vrši samo u njemu.

PG10: prvi pokušaj

Ali particioniranje putem nasljeđivanja povijesno nije bilo prikladno za rad s aktivnim tokom pisanja ili velikim brojem podređenih particija. Na primjer, možete se sjetiti da je algoritam za odabir potrebnog odjeljka imao kvadratna složenost, da radi sa 100+ odjeljaka, sami razumijete kako...

U PG10 ova je situacija uvelike optimizirana implementacijom podrške izvorno particioniranje. Stoga smo ga odmah pokušali primijeniti odmah nakon migracije pohrane, ali...

Kao što se pokazalo nakon kopanja po priručniku, nativno particionirana tablica u ovoj verziji je:

  • ne podržava indeksne opise
  • ne podržava okidače na njemu
  • ne može biti ničiji "potomak"
  • ne podržavaju INSERT ... ON CONFLICT
  • ne može automatski generirati odjeljak

Dobivši bolan udarac grabljama u čelo, shvatili smo da je nemoguće bez izmjene aplikacije i odgodili daljnja istraživanja za šest mjeseci.

PG10: druga prilika

Dakle, počeli smo rješavati probleme koji su se pojavili jedan po jedan:

  1. Budući da izaziva i ON CONFLICT Utvrdili smo da nam tu i tamo još trebaju, pa smo napravili međufazu da ih razradimo proxy tablica.
  2. Riješili smo se "usmjeravanja" u okidačima – odnosno iz EXECUTE.
  3. Odvojeno su ga izvadili predloška tablice sa svim indeksimatako da nisu ni prisutni u proxy tablici.

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB
Konačno, nakon svega ovoga, glavni stol smo pregradili nativno. Izrada nove rubrike ipak je prepuštena savjesti aplikacije.

“Piljenje” rječnika

Kao i u svakom analitičkom sustavu, imali smo i mi "činjenice" i "rezovi" (rječnici). U našem slučaju u tom su svojstvu djelovali npr. tijelo predloška slične spore upite ili tekst samog upita.

“Činjenice” su već odavno podijeljene po danima, pa smo mirno brisali zastarjele rubrike i nisu nam smetale (logovi!). Ali bio je problem s rječnicima...

Ne da kažem da ih je bilo puno, ali otprilike 100TB “činjenica” rezultiralo je rječnikom od 2.5TB. Iz takve tablice ne možete jednostavno ništa izbrisati, ne možete je komprimirati u odgovarajućem vremenu, a pisanje u nju postupno je postalo sporije.

Kao u rječniku... u njemu svaka natuknica treba biti predstavljena točno jednom... i to je točno, ali!.. Nitko nam ne brani da imamo poseban rječnik za svaki dan! Da, ovo donosi određenu redundantnost, ali omogućuje:

  • pisati/čitati brže zbog manje veličine presjeka
  • troše manje memorije radom s kompaktnijim indeksima
  • pohraniti manje podataka zbog mogućnosti brzog uklanjanja zastarjelih

Kao rezultat cijelog kompleksa mjera CPU opterećenje smanjeno za ~30%, opterećenje diska za ~50%:

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB
U isto vrijeme, nastavili smo pisati potpuno istu stvar u bazu podataka, samo s manje opterećenja.

#2. Evolucija baze podataka i refaktoriranje

Pa smo pristali na ono što imamo svaki dan ima svoj dio s podacima. Zapravo, CHECK (dt = '2018-10-12'::date) — i tu je ključ particioniranja i uvjet da zapis padne u određeni odjeljak.

Budući da su sva izvješća u našoj usluzi izgrađena u kontekstu određenog datuma, indeksi za njih od "neparticioniranih vremena" bili su svih vrsta (poslužitelj, datum, Predložak plana), (poslužitelj, datum, čvor plana), (datum, klasa pogreške, poslužitelj), ...

Ali sada žive na svakom dijelu svoje kopije svaki takav indeks... I unutar svakog odjeljka datum je konstanta... Ispada da smo sada u svakom takvom indeksu jednostavno unesite konstantu kao jedno od polja, što mu povećava i volumen i vrijeme traženja, ali ne donosi nikakav rezultat. Grablje su ostavili sebi, ups...

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB
Smjer optimizacije je očit – jednostavan uklonite polje datuma iz svih indeksa na pregrađenim stolovima. S obzirom na naše količine, dobitak je otprilike 1TB/tjedan!

Napomenimo sada da je taj terabajt ipak trebalo nekako snimiti. Odnosno i mi disk bi sada trebao manje učitavati! Ova slika jasno pokazuje učinak čišćenja kojem smo posvetili tjedan dana:

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB

#3. “Širenje” vršnog opterećenja

Jedan od velikih problema opterećenih sustava je redundantna sinkronizacija neke operacije koje to ne zahtijevaju. Ponekad "jer nisu primijetili", ponekad "bilo je lakše tako", ali prije ili kasnije toga se morate riješiti.

Povećajmo prethodnu sliku i vidimo da imamo disk “pumpa” pod opterećenjem s dvostrukom amplitudom između susjednih uzoraka, što se jasno “statistički” ne bi smjelo dogoditi s tolikim brojem operacija:

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB

To je prilično lako postići. Već smo započeli praćenje gotovo 1000 poslužitelja, svaku obrađuje zasebna logička nit, a svaka nit resetira akumulirane informacije koje se šalju u bazu podataka određenom učestalošću, otprilike ovako:

setInterval(sendToDB, interval)

Problem ovdje leži upravo u tome što sve niti počinju približno u isto vrijeme, tako da se njihova vremena slanja gotovo uvijek podudaraju "točno". Ups #2...

Srećom, ovo je prilično lako popraviti, dodavanje "slučajnog" zaleta s vremenom:

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

#4. Spremamo ono što nam treba

Treći tradicionalni problem velikog opterećenja je nema predmemorije gdje je on mogao biti.

Na primjer, omogućili smo analizu u smislu čvorova plana (svi ovi Seq Scan on users), ali odmah pomisle da su, uglavnom, isti – zaboravili su.

Ne, naravno, ništa se više ne upisuje u bazu podataka, ovo prekida okidač s INSERT ... ON CONFLICT DO NOTHING. Ali ti podaci ipak dospijevaju u bazu podataka i nepotrebni su čitanje radi provjere sukoba morati učiniti. Ups #3...

Razlika u broju zapisa koji se šalju u bazu podataka prije/nakon što je omogućeno predmemoriranje je očita:

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB

A ovo je popratni pad opterećenja pohrane:

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB

Ukupno

"Terabajt po danu" jednostavno zvuči zastrašujuće. Ako sve učiniš kako treba, onda je ovo pravedno 2^40 bajtova / 86400 sekundi = ~12.5 MB/sda su čak i desktop IDE vijci izdržali. 🙂

Ali ozbiljno, čak i s deseterostrukim "iskrivljenjem" opterećenja tijekom dana, lako možete zadovoljiti mogućnosti modernih SSD-ova.

Pišemo u PostgreSQL na sublight: 1 host, 1 dan, 1TB

Izvor: www.habr.com

Dodajte komentar