Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB

Hiljuti rääkisin, kuidas on võimalik kasutada tüüpilisi retsepte SQL-päringute lugemise tulemuslikkuse suurendamiseks PostgreSQL-andmebaasist. Täna räägime sellest, kuidas saab andmete kirjutamist andmebaasi muuta efektiivsemaks, ilma et oleks vaja kasutada mingisuguseid "nuppe" konfiguratsioonis — lihtsalt korraldades andmevooge õigesti.

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB

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

Artikkel sellest, kuidas ja miks tuleks korraldada rakenduslikku sektsioonimist „teoorias” on juba olemas, siin räägime aga mõningate lähenemiste rakendamisest meie PostgreSQL-serverite sajade jälgimise teenuse.

„Aegade alguses...”

Algul, nagu iga MVP puhul, käivitus meie projekt suhteliselt väikese koormuse all — jälgimine toimus vaid kümne tähtsama serveri jaoks, kõik tabelid olid suhteliselt kompaktsed... Kuid aeg läks edasi, jälgitavate hostide arv kasvas ja üritades jälle midagi teha ühega tabelitest, mille suurus on 1,5 TB, mõistsime, et elu nii jätkata on küll võimalik, kuid väga ebamugav.

Ajad olid peaaegu müütilised, toona olid aktuaalsed erinevad PostgreSQL 9.x variandid, seega tuli kogu sektsioonimine teha "käsitsi" — läbi tabelite pärimise ja trigerite dünaamilise suunamisega. TEOSTA.

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB
Saadud lahendus osutus piisavalt universaalseks, et seda saaks rakendada kõigi tabelite jaoks:

  • Käivitasime tühi "pealkirja" vanematabeli, millel olid kõik vajalikud indeksid ja triggarid..
  • Klient saadab kirje "juurtabelisse", seestpoolt aga läbi suunava triggeri BEFORE INSERT saadi kirje „füüsiliselt” vajalikku sektsiooni. Kui sellist sektsiooni ei olnud — püüdsime erandi ja ...
  • ... abiga CREATE TABLE ... (LIKE ... INCLUDING ...) moodustati sektor soovitud kuupäeva piiranguga, et andmete väljavõtmise ajal toimuks lugemine ainult seal.

PG10: esimene katse

Kuid pärimise kaudu sektsioonimine ei olnud ajaloos väga kohandatud aktiivse kirjutusvoo või suure arvu alamsektsioonide jaoks. Näiteks võib meenutada, et vajaliku sektsiooni valimise algoritm oli ruudulise keerukusega, mis 100+ sektsiooni puhul töötab, nagu aru saate....

PG10-s optimeeriti seda olukorda oluliselt, rakendades toe natiivsele sektsioonimisele.. Seetõttu proovisime seda kohe rakendada pärast salvestuse migreerimist, kuid…

Kuidas selgus pärast manuaali uurimist, ei toeta selle versiooni kohandatud sektsioneeritud tabel:

  • ei toeta indeksite kirjeldust
  • ei toeta sellel triggerite olemasolu
  • ei saa olla kellelegi «järeltulijaks»
  • ei toeta INSERT ... ON CONFLICT
  • ei oska automaatselt sektsiooni luua

Pärast peaga vastu hambaid saamist mõistsime, et ilma rakenduse modifitseerimiseta ei saa ikka hakkama ja lükkasime edasi edasised uuringud kuueks kuuks.

PG10: teine võimalus

Nii hakkasime probleeme järk-järgult lahendama:

  1. Kuna triggerid ja ON CONFLICT olid meil siiski vajalikud, koostasime vahendustabeli proxy-tabeli.
  2. Vabastasime end «routimisest» triggerites—ehk siis TEOSTA.
  3. Tootsime eraldi šabloontabeli kõigi indeksitega, et need isegi proxy-tabelis puuduksid.

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB
Lõpuks, pärast kogu seda teed, saime kohandatud sektsiooniga peamise tabeli lõplikult külge. Uue sektsiooni loomine jäi rakenduse vastutada.

«Laitseme» sõnastikke

Nagu igas analüüsisüsteemis, olid meil ka «faktid» ja «lõike» (sõnastikud). Meie puhul oli näideteks näiteks šablooni «keha» ühtlastest aeglastest päringutest või päringu enda tekstist.

«Faktid» olid meil päevaste järgi juba ammu sektsioneeritud, seega eemaldasin rahulikult aegunud osad, nad ei seganud meid (logid ju!). Kuid sõnastikega tekkis probleeme…

Ei saa öelda, et neid oleks väga palju olnud, kuid umbes 100 TB «faktide» kohta saime sõnastiku suuruseks 2,5 TB.. Sellisest tabelist ei olnud mugav midagi eemaldada, aeglaselt ja tõhusalt, ning isegi andmete sisestamine muutus järjest aeglasemaks.

Nagu ka sõnastik… igal salvestusel peaks olema täpselt üks kord olemas… ja see on õige, kuid! Keegi ei takista meid omamast erinevat sõnastikku iga päeva kohta! Jah, see toob kaasa teatud ülemäärasuse, kuid võimaldab:

  • kirjutada/looda kiiremini väiksema osade suuruse tõttu
  • tarbida vähem mälu kompaktsemate indeksitega töötamise tõttu
  • hoida vähem andmeid aegunud kiire eemaldamise võimaluse tõttu

Kogu tegevuste komplekti tulemusena CPU koormus vähenes ~30% ja kettakoormus ~50%:

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB
Samas jätkasime andmebaasi kirjutamist täpselt sama, lihtsalt väiksema koormusega.

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

Nii et, me jõudsime järeldusele, et meil on iga päeva jaoks oma sektsioon andmetega. Tegelikult, CHECK (dt = '2018-10-12'::date) — ja see on sektsioneerimise võti ning tingimus, mille kohaselt kirje satuvad konkreetse sektsiooni.

Kuna kõik meie teenuse aruanded koostatakse konkreetse kuupäeva lõikes, siis olid ka seadmed juba "mitte-sektsioneeritud aegadel" kõik tüüpi (Server, Kuupäev, Plaani mall), (Server, Kuupäev, Plaani sõlm), (Kuupäev, Veaklass, Server),…

Aga nüüd elavad igas sektsioonis oma eksemplarid iga sellise seadme kohta... Ja iga sektsiooni raames kuupäev on konstant… Tundub, et nüüd kirjutame igasse sellesse seadmesse tüüpiliselt konstant ühe väljana, mis tõstab nii selle mahtu kui ka otsimise aega, kuid ei too mingeid tulemusi. Jätame endale ise probleemi, ups…

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB
Optimeerimise suund on ilmselge — lihtsalt eemaldame väljad kuupäeva kõikidest seadmetest sektsioneeritud tabelites. Meie mahtude puhul on kokkuhoid umbes 1TB/nädalas!

Ja nüüd märkame, et see terabait tuleb ka kuidagi salvestada. See tähendab, et me peame nüüd kettalt vähem koormust võtma! Sellel pildil on hästi nähtav saadud efekt läbi viidud puhastusest, millele pühendasime nädala:

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB

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

Üks suur probleem koormatud süsteemides on ülemäärane sünkroonimine mõnede toimingute osas, mis seda ei nõua. Mõnikord "sest ei märganud", mõnikord "niimoodi oli lihtsam", kuid varem või hiljem tuleb sellest vabaneda.

Suurendame eelmist pilti — ja näeme, et meie ketas "tõmbab" koormust kahekordse amplituudiga kõrvuti olevate mõõtmiste vahel, mis "statistiliselt" ei tohiks olla sellise tegevuste arvu juures:

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB

Seda on piisavalt lihtne saavutada. Meie jälgimisel oli juba peaaegu 1000 serverit, igaüks töödeldakse eraldi loogilise vooguna ja iga voog edastab kogunenud teabe andmebaasi teatud perioodilisusega, umbes nii:

setInterval(sendToDB, interval)

Probleem peitub just selles, et kõik voogud käivitatakse peaaegu samal ajal, seega nende saatmise hetked langevad peaaegu alati kokku "punkti". Ups nr 2…

Õnneks on seda piisavalt lihtne parandada, lisades "juhuslikku" hajutust ajaliselt:

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

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

Kolmas traditsiooniline probleem kõrge koormusega — vähem koodi seal, kus see saaksin peaks olema.

Näiteks oleme teinud võimaluse analüüsida plaanide sõlmede lõikes (kõik need Seq Skannimine kasutajate peal), kuid kohe mõelda, et need on massiliselt sarnased — unustasid.

Ei, muidugi ei kirjutata andmebaasi midagi uuesti, see katkestab triggereid INSERT ... ON CONFLICT DO NOTHING. Kuid andmed jõuavad andmebaasi ikka, ning lisaks sellele on üleliigne lugemine konflikti kontrollimiseks tuleb ikkagi teha. Ups №3...

Erinevus andmebaasi saadetud kirjeid arvestades enne/peale vahemälude aktiveerimist — on ilmne:

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB

Ja see — kaasnev koormuse langus salvestis:

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB

Kokkuvõttes

«Terabaidid-päevas» kõlab hirmuäratavalt. Kui teete kõik õigesti, siis on see vaid 2^40 baiti / 86400 sekundit = ~12.5MB/s, mida suutsid isegi lauaarvuti IDE-kettad. 🙂

Aga tõsiselt rääkides, isegi kümnekordse koormuse „kaldumise“ korral päevas, saate rahulikult jääda tänapäevaste SSD-de võimaluste piiresse.

Kirjutame PostgreSQL-is valguskiirusel: 1 host, 1 päev, 1TB

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster