Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt

Äskettäin kerroin sinulle, kuinka tavallisten reseptien avulla parantaa SQL-lukukyselyjen suorituskykyä PostgreSQL-tietokannasta. Tänään puhumme kuinka tallennus voidaan tehdä tehokkaammin tietokannassa käyttämättä mitään "käänteitä" konfiguraatiossa - yksinkertaisesti järjestämällä tietovirrat oikein.

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt

#1. Leikkaaminen

Artikkeli siitä, miten ja miksi se kannattaa järjestää sovellettu osiointi "teoriassa" on jo ollut, tässä puhumme käytännöstä soveltaa joitakin lähestymistapoja omassamme seurantapalvelu sadoille PostgreSQL-palvelimille.

"Asioita menneistä päivistä..."

Aluksi, kuten mikä tahansa MVP, projektimme alkoi melko kevyellä kuormituksella - valvontaa tehtiin vain kymmenelle kriittisimmälle palvelimelle, kaikki taulukot olivat suhteellisen kompakteja... Mutta ajan myötä valvottujen isäntien määrä kasvoi koko ajan , ja jälleen kerran yritimme tehdä jotain yhden kanssa pöydät kooltaan 1.5TB, ymmärsimme, että vaikka oli mahdollista jatkaa elämää näin, se oli erittäin epämukavaa.

Ajat olivat melkein kuin eeppisiä aikoja, PostgreSQL 9.x:n eri versiot olivat merkityksellisiä, joten kaikki osiointi piti tehdä "manuaalisesti" - läpi taulukon periytyminen ja laukaisimet reititys dynaamisella EXECUTE.

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt
Tuloksena oleva ratkaisu osoittautui tarpeeksi universaaliksi, jotta se voidaan kääntää kaikkiin taulukoihin:

  • Tyhjä "otsikko"-emotaulukko ilmoitettiin, joka kuvasi kaiken tarvittavat indeksit ja triggerit.
  • Tietue asiakkaan näkökulmasta tehtiin "juuri"-taulukkoon ja sisäisesti käyttäen reititysliipaisin BEFORE INSERT tietue lisättiin "fyysisesti" vaadittuun osioon. Jos sellaista ei vielä ollut, saimme poikkeuksen ja...
  • … käyttämällä CREATE TABLE ... (LIKE ... INCLUDING ...) luotiin emotaulukon mallin perusteella osio, jossa on rajoitus haluttuun päivämääräänniin, että kun dataa haetaan, luetaan vain siinä.

PG10: ensimmäinen yritys

Mutta osiointi perinnön kautta ei ole historiallisesti soveltunut hyvin aktiivisen kirjoitusvirran tai suuren määrän aliosioita käsittelemiseen. Voit esimerkiksi muistaa, että tarvittavan osion valinnan algoritmilla oli neliöllinen monimutkaisuus, että se toimii yli 100 osion kanssa, ymmärrät itse kuinka...

PG10:ssä tämä tilanne optimoitiin suuresti ottamalla käyttöön tuki natiivi osiointi. Siksi yritimme heti ottaa sen käyttöön heti tallennustilan siirron jälkeen, mutta...

Kuten käsikirjan kaivamisen jälkeen kävi ilmi, natiivisti osioitu taulukko tässä versiossa on:

  • ei tue hakemistokuvauksia
  • ei tue laukaisimia siinä
  • ei voi olla kenenkään "jälkeläinen"
  • älä tue INSERT ... ON CONFLICT
  • ei voi luoda osiota automaattisesti

Saatuamme tuskallisen iskun otsaan haravalla, ymmärsimme, että ilman hakemuksen muokkaamista se olisi mahdotonta, ja lykkäsimme jatkotutkimusta kuudella kuukaudella.

PG10: toinen mahdollisuus

Joten aloimme ratkaisemaan esiin tulleita ongelmia yksitellen:

  1. Koska laukaisee ja ON CONFLICT Huomasimme, että tarvitsemme niitä edelleen siellä täällä, joten teimme välivaiheen niiden laatimiseksi välityspalvelintaulukko.
  2. Päästiin eroon "reitittämisestä" laukaisimissa - eli alkaen EXECUTE.
  3. He ottivat sen pois erikseen mallitaulukko, jossa on kaikki indeksitniin, että ne eivät ole edes läsnä välityspalvelintaulukossa.

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt
Lopuksi kaiken tämän jälkeen osioitimme päätaulukon natiivisti. Uuden osion luominen jätetään edelleen sovelluksen omalletunnolle.

"Sahaus" sanakirjat

Kuten kaikissa analyyttisissä järjestelmissä, myös meillä oli "fakta" ja "leikkaukset" (sanakirjat). Meidän tapauksessamme he toimivat tässä ominaisuudessa mm. mallin runko vastaavia hitaita kyselyitä tai itse kyselyn tekstiä.

”Faktat” jaettiin päiväkohtaisesti jo pitkään, joten vanhentuneet osiot poistettiin rauhallisesti, eivätkä ne meitä häirinneet (lokit!). Mutta sanakirjojen kanssa oli ongelma...

En tarkoita, että niitä olisi ollut paljon, mutta suunnilleen 100 Tt "faktoja" johti 2.5 Tt:n sanakirjaan. Tällaisesta taulukosta ei voi kätevästi poistaa mitään, et voi pakata sitä riittävän ajoissa, ja siihen kirjoittaminen hidastui vähitellen.

Kuten sanakirja... siinä jokainen merkintä pitäisi esittää täsmälleen kerran... ja tämä on oikein, mutta!.. Kukaan ei estä meitä saamasta joka päivä erillinen sanakirja! Kyllä, tämä tuo tietyn redundanssin, mutta se mahdollistaa:

  • kirjoittaa/lukea nopeammin pienemmän osan koon vuoksi
  • kuluttaa vähemmän muistia työskentelemällä kompaktimpien indeksien kanssa
  • tallentaa vähemmän dataa johtuen kyvystä poistaa vanhentuneet nopeasti

Koko toimenpidekokonaisuuden seurauksena Suorittimen kuormitus laski ~30 %, levykuorma ~50 %:

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt
Samaan aikaan jatkoimme täsmälleen saman asian kirjoittamista tietokantaan, vain pienemmällä kuormituksella.

#2. Tietokannan kehitys ja uudelleenmuodostus

Joten päädyimme siihen, mitä meillä on joka päivä on oma osio datan kanssa. Itse asiassa, CHECK (dt = '2018-10-12'::date) — ja siinä on osiointiavain ja ehto tietueen kuulumiselle tiettyyn osioon.

Koska kaikki palvelumme raportit on rakennettu tietyn päivämäärän yhteydessä, niiden indeksit ovat olleet "osioimattomista ajoista" lähtien kaikenlaisia (Palvelin, Päivämäärä, Suunnitelmamalli), (Palvelin, Päivämäärä, Suunnitelma solmu), (Päivämäärä, Virheluokka, Palvelin), ...

Mutta nyt he elävät joka puolella sinun kopiot jokainen tällainen hakemisto... Ja jokaisessa osiossa päivämäärä on vakio... Osoittautuu, että nyt olemme jokaisessa tällaisessa indeksissä syötä vain vakio yhtenä kentistä, mikä lisää sekä sen määrää että hakuaikaa, mutta ei tuota tulosta. He jättivät haravan itselleen, oho...

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt
Optimoinnin suunta on ilmeinen - yksinkertainen poista päivämääräkenttä kaikista hakemistoista osioiduilla pöydillä. Kun otetaan huomioon volyymimme, voitto on noin 1TB/viikko!

Huomattakoon nyt, että tämä teratavu piti silti tallentaa jotenkin. Eli myös me levyn pitäisi nyt ladata vähemmän! Tässä kuvassa näkyy selkeästi siivouksesta saatu vaikutus, jolle omistimme viikon:

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt

#3. Huippukuorman "levittäminen".

Yksi ladattujen järjestelmien suurista ongelmista on redundantti synkronointi jotkin toiminnot, jotka eivät vaadi sitä. Joskus "koska he eivät huomanneet", joskus "se oli helpompaa niin", mutta ennemmin tai myöhemmin siitä on päästävä eroon.

Zoomataan edellistä kuvaa ja katsotaan, että meillä on levy "pumppaa" kuorman alle kaksinkertaisella amplitudilla vierekkäisten näytteiden välillä, mitä selvästi "tilastollisesti" ei pitäisi tapahtua tällaisella määrällä operaatioita:

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt

Tämä on melko helppo saavuttaa. Olemme jo aloittaneet seurannan lähes 1000 palvelinta, jokaista käsitellään erillisellä loogisella säikeellä, ja jokainen säie nollaa tietokantaan lähetettävät kertyneet tiedot tietyllä taajuudella, jotenkin näin:

setInterval(sendToDB, interval)

Ongelma tässä on juuri siinä tosiasiassa kaikki langat alkavat suunnilleen samaan aikaan, joten niiden lähetysajat ovat melkein aina samat "pisteeseen". Oho #2...

Onneksi tämä on melko helppo korjata, lisäämällä "satunnainen" käynnistys ajan kanssa:

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

#4. Tallennamme välimuistiin mitä tarvitsemme

Kolmas perinteinen kuormitusongelma on ei välimuistia missä hän on voisi olla.

Teimme esimerkiksi mahdollisuuden analysoida suunnitelmasolmujen suhteen (kaikki nämä Seq Scan on users), mutta ajattele heti, että ne ovat suurimmaksi osaksi samoja - he unohtivat.

Ei tietenkään, tietokantaan ei kirjoiteta taas mitään, tämä katkaisee liipaisimen INSERT ... ON CONFLICT DO NOTHING. Mutta nämä tiedot pääsevät silti tietokantaan, ja se on tarpeetonta lukeminen ristiriitojen tarkistamiseksi pitää tehdä. Oho #3...

Ero tietokantaan lähetettyjen tietueiden lukumäärässä ennen/jälkeen välimuistin käyttöönoton on ilmeinen:

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt

Ja tämä on mukana säilytyskuorman lasku:

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt

Yhteensä

"Terabyte-per-day" kuulostaa vain pelottavalta. Jos teet kaiken oikein, tämä on oikein 2^40 tavua / 86400 sekuntia = ~12.5 Mt/settä jopa työpöydän IDE-ruuvit pitivät. 🙂

Mutta vakavasti, jopa kymmenkertaisella "vinollaan" kuormituksella päivän aikana, voit helposti täyttää nykyaikaisten SSD-levyjen ominaisuudet.

Kirjoitamme PostgreSQL:llä sublightille: 1 isäntä, 1 päivä, 1 Tt

Lähde: will.com

Lisää kommentti