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

Nedavno sam pričao o tome kako standardni recepti povećavaju performanse SQL upita "za čitanje" iz PostgreSQL baze. Danas ćemo razgovarati o tome kako učiniti zapis u Bazi podataka efikasnijim bez korištenja bilo kakvih "okvira" u konfiguraciji — samo pravilno organizirajući tokove podataka.

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

#1. Секционирование

Članak o tome kako i zašto je važno organizirati praktično sekcioniranje "u teoriji" već je bio, ovdje ćemo govoriti o primjeni nekih pristupa u okviru našeg servisa za praćenje stotina PostgreSQL servera.

"Stari dani..."

Izvorno, kao i svaki MVP, naš projekt je započeo pod prilično malim opterećenjem — praćenje se vršilo samo za desetero najkritičnijih servera, sve tablice su bile relativno kompaktne... Ali vrijeme je prolazilo, broj praćenih hostova je rastao, i pokušavajući još jednom nešto učiniti s jednom od tablica veličine 1.5TB, shvatili smo da je moguće živjeti tako, ali veoma nezgodno.

Dani su bili gotovo bajkoviti, korištene su različite verzije PostgreSQL 9.x, tako da je cijelo sekcioniranje moralo biti rađeno "ručno" — putem nasljeđivanja tablica i okidača rute s dinamičkim EXECUTE.

Pišemo u PostgreSQL na subluminaciji: 1 host, 1 dan, 1TB.
Konačno rješenje je bilo dovoljno univerzalno da se može primijeniti na sve tablice:

  • Objavljena je prazna "zaglavna" roditeljska tablica, na kojoj su opisani svi potrebni indeksi i okidači.
  • Zapis s gledišta klijenta vršen je u "korijensku" tablicu, a unutar uz pomoć okidača rute BEFORE INSERT zapis je "fizički" umetnut u potrebnu sekciju. Ako sekcija još nije postojala — uhvatili smo izuzetak i …
  • … uz pomoć CREATE TABLE ... (LIKE ... INCLUDING ...) po uzorku roditeljske tablice stvarala se sekcija s ograničenjem na potrebni datum, kako bi se prilikom izvlačenja podataka čitanje vršilo samo u njoj.

PG10: prvi pokušaj

Međutim, sekcioniranje putem nasljeđivanja historijski nije bilo vrlo prilagođeno za rad s aktivnim tokom zapisa ili velikim brojem sekcija-potomaca. Na primjer, može se sjetiti da je algoritam izbora potrebne sekcije imao kvadratnu složenost, što uz 100+ sekcija radi, sami razumijete kako...

U PG10 je ova situacija značajno optimizirana, implementirajući podršku nativnom sekcioniranju. Stoga smo ga odmah pokušali primijeniti odmah nakon migracije pohrane, ali…

Kako smo saznali nakon pretraživanja vodiča, nativno sekcionirana tablica u ovoj verziji:

  • ne podržava opis indeksa
  • ne podržava okidače
  • ne može biti ničiji "potomak"
  • ne podržava INSERT ... ON CONFLICT
  • ne može automatski generirati sekciju

Bolno udarivši o dno, shvatili smo da bez modifikacije aplikacije nećemo moći proći, i odložili daljnja istraživanja na pola godine.

PG10: druga prilika

Dakle, počeli smo rješavati nastale probleme redom:

  1. Budući da su okidači i ON CONFLICT pokazali se potrebnima na nekoliko mjesta, za njihovo izvršavanje napravili smo privremenu proksi-tablicu.
  2. Riješili smo se "rutiranja" u okidačima — odnosno od EXECUTE.
  3. Izvukli smo odvojeno predložak-tablicu sa svim indeksima, tako da oni čak nisu ni prisutni na proksi-tablici.

Pišemo u PostgreSQL na subluminaciji: 1 host, 1 dan, 1TB.
Napokon, nakon svega toga, nativno smo sekcionirali glavnu tablicu. Stvaranje nove sekcije za sada je ostalo na savjesti aplikacije.

"Režemo" rječnike

Kao i u svakom analitičkom sustavu, imali smo i mi "činjenice" i "rezove" (rječnici). U našem slučaju, kao takvi, pojavili su se, na primjer, tijelo "predloška" jednoličnih sporih upita ili tekst samog upita.

"Činjenice" su nam već bile sekcionirane po danima, tako da smo mirno brisali zastarjele sekcije, a one nam nisu smetale (logovi!). Ali, s rječnicima je bio problem...

Ne može se reći da ih je bilo previše, ali otprilike na 100TB "činjenica" dobio se rječnik od 2.5TB.. Iz takve tablice nije lako ništa izbrisati, ni komprimirati u razumnom vremenu, a i zapis u nju postajao je sve sporiji.

Izgleda kao rječnik… u njemu bi svaki zapis trebao biti predstavljen upravo jednom… i to je točno, ali!.. Nitko nam ne brani imati po jedan rječnik za svaki dan! Da, to donosi određenu suvišnost, ali omogućuje:

  • brže pisanje/čitanje zahvaljujući manjoj veličini sekcije
  • trošiti manje memorije zbog rada s kompaktnijim indeksima
  • pohraniti manje podataka zahvaljujući mogućnosti brzog brisanja zastarjelih

Kao rezultat cijelog kompleksa mjera opterećenje CPU-a smanjeno je za ~30%, na disku — za ~50%:

Pišemo u PostgreSQL na subluminaciji: 1 host, 1 dan, 1TB.
Nastavili smo zapisivati u bazu iste podatke, ali s manjim opterećenjem.

#2. Эволюция и рефакторинг БД

Dakle, stali smo na tome da imamo sekciju za svaki dan s podacima. U suštini, CHECK (dt = '2018-10-12'::date) je ključ sekcioniranja i uvjet koji određuje upisivanje zapisa u konkretnu sekciju.

Budući da se svi izvještaji u našoj usluzi kreiraju prema određenom datumu, indeksi iz "nesekcioniranih vremena" također su bili svi (Server, Datum, Predložak plana), (Server, Datum, Čvor plana), (Datum, Klasa pogreške, Server),…

No sada svaka sekcija ima svoje instance svakog od tih indeksa… I unutar svake sekcije datum je konstantan… Dakle, sada jednostavno upisujemo konstantu kao jedno od polja u svaki takav indeks, što povećava i njegovu veličinu i vrijeme pretraživanja, ali ne donosi ništa korisno. Ostavili smo sebi zamke, ups… Pristup optimizaciji je očigledan — jednostavno

Pišemo u PostgreSQL na subluminaciji: 1 host, 1 dan, 1TB.
uklanjamo polje s datumom iz svih indeksa na sekcioniranim tablicama. U našim količinama, dobitak je otprilike 1TB/tjedan A sada primijetimo da tu terabajt još treba nekako zapisati. To znači da dodatno!

disk također treba manje opterećivati ! Na ovoj slici dobro se vidi postignuti učinak nakon čišćenja kojem smo posvetili tjedan:Jedna od velikih problema opterećenih sustava je

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

#3. «Размазываем» пиковую нагрузку

višak sinkronizacije nepotrebnih operacija. Ponekad "jer nisu primijetili", ponekad "jer je tako bilo lakše", ali prije ili kasnije to se mora eliminirati. Približimo prethodnu sliku — i vidimo da naš disk

ima "opterećenje" s dvostrukom amplitudom između susjednih mjerenja, što očito "statistički" ne bi smjelo biti pri tolikom broju operacija: To je dovoljno lako postići. Naš nadzor obuhvatio je već

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

skoro 1000 servera , svaki od njih obrađuje se zasebnim logičkim tokom, a svaki tok pohranjuje akumulirane informacije za slanje u bazu s određenom periodičnošću, otprilike ovako:setInterval(sendToDB, interval)

Problemi su suštinski u tome da

svi tokovi započinju otprilike u isto vrijeme , pa se trenuci slanja gotovo uvijek poklapaju "do tačke". Ups br. 2…Na sreću, to se može lako ispraviti,

dodavanjem "slučajne" razlike u vremenu: po vremenu:

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

#4. Кэшируем, что нужно можно

Treći tradicionalni problem visokog opterećenja — nedostatak predmemorije tamo gdje bi on mogao biti.

Na primjer, omogućili smo analizu po čvorovima plana (svi ovi Seq Scan on users), ali odmah pomisliti da su oni, u masi, isti — zaboravili smo.

Ne, naravno, u bazu se ništa ne piše ponovo, to odbacuje okidač s INSERT ... ON CONFLICT DO NOTHING. Ali do baze ti podaci ipak dolaze, a i nepotrebno čitanje za provjeru sukoba moramo raditi. Ups br. 3…

Razlika u broju zapisa poslanih u bazu prije/poslije uključivanja predmemorije — očita je:

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

A ovo je — prateći pad opterećenja na skladištu:

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

U konačnici

„Terabajt-u-dan“ samo zvuči strašno. Ako sve radite ispravno, to je samo 2^40 bajtova / 86400 sekundi = ~12.5MB/s, što su čak i stolni IDE diskovi mogli održati. 🙂

A ako govorimo ozbiljno, čak i uz deseterostruko „iskrivljenje“ opterećenja tijekom dana, možete se lako uklopiti u mogućnosti modernih SSD-a.

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

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster