Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB

Lastatempe mi rakontis al vi kiel, uzante normajn receptojn pliigi la rendimenton de SQL-legaj demandoj el PostgreSQL-datumbazo. Hodiaŭ ni parolos pri kiel registrado povas esti farita pli efike en la datumbazo sen uzi iujn ajn "tordaĵojn" en la agordo - simple ĝuste organizante la datumfluojn.

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB

#1. Sekciado

Artikolo pri kiel kaj kial ĝi indas organizi aplikata dispartigo "teorie" jam estis, ĉi tie ni parolos pri la praktiko apliki iujn alirojn ene de nia monitora servo por centoj da PostgreSQL-serviloj.

"Aferoj de pasintaj tagoj..."

Komence, kiel ĉiu MVP, nia projekto komenciĝis sub sufiĉe malpeza ŝarĝo - monitorado estis farita nur por la dek plej kritikaj serviloj, ĉiuj tabeloj estis relative kompaktaj... Sed kun la tempo, la nombro da monitoritaj gastigantoj fariĝis pli kaj pli. , kaj denove ni provis fari ion kun unu el tabloj 1.5TB en grandeco, ni konstatis, ke kvankam eblis plu vivi tiel, ĝi estis tre maloportune.

La tempoj estis preskaŭ kiel epopeaj tempoj, malsamaj versioj de PostgreSQL 9.x estis trafaj, do ĉiuj dispartigo devis esti farita "mane" - tra tabelheredaĵo kaj ellasiloj vojigo kun dinamika EXECUTE.

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB
La rezulta solvo montriĝis sufiĉe universala, ke ĝi povus esti tradukita al ĉiuj tabeloj:

  • Malplena "kapo" gepatra tablo estis deklarita, kiu priskribis ĉion necesaj indeksoj kaj ellasiloj.
  • La registro de la vidpunkto de la kliento estis farita en la "radiko" tabelo, kaj interne uzante enruta ellasilo BEFORE INSERT la rekordo estis "fizike" enigita en la postulatan sekcion. Se ankoraŭ ne ekzistis tia afero, ni kaptis escepton kaj...
  • … uzante CREATE TABLE ... (LIKE ... INCLUDING ...) estis kreita surbaze de la ŝablono de la gepatra tabelo sekcio kun limigo pri la dezirata datotiel ke kiam datumoj estas prenitaj, legado estas farita nur en ĝi.

PG10: unua provo

Sed dispartigo per heredo historie ne tre taŭgas por labori kun aktiva skribfluo aŭ granda nombro da postdiskdiskoj. Ekzemple, vi povas memori, ke la algoritmo por elekti la bezonatan sekcion havis kvadrata komplekseco, ke ĝi funkcias kun 100+ sekcioj, vi mem komprenas kiel...

En PG10 ĉi tiu situacio estis tre optimumigita per efektivigo de subteno denaska dispartigo. Tial ni tuj provis apliki ĝin tuj post la migrado de la stokado, sed...

Kiel montriĝis post fosado de la manlibro, la denaske dividita tablo en ĉi tiu versio estas:

  • ne subtenas indeksajn priskribojn
  • ne subtenas ellasilon sur ĝi
  • ne povas esti ies "posteulo"
  • ne subtenas INSERT ... ON CONFLICT
  • ne povas generi sekcion aŭtomate

Ricevinte doloran baton al la frunto per rastilo, ni komprenis, ke ne eblas fari sen modifo de la aplikaĵo, kaj prokrastis pliajn esplorojn por ses monatoj.

PG10: dua ŝanco

Do, ni komencis solvi la problemojn, kiuj aperis unu post la alia:

  1. Ĉar ellasiloj kaj ON CONFLICT Ni trovis, ke ni ankoraŭ bezonas ilin tie kaj tie, do ni faris mezan etapon por ellabori ilin prokura tablo.
  2. Foriĝis de "vojigo" en ellasiloj - tio estas de EXECUTE.
  3. Ili elprenis ĝin aparte ŝablona tabelo kun ĉiuj indeksojtiel ke ili eĉ ne ĉeestas en la prokura tabelo.

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB
Fine, post ĉio ĉi, ni dividis la ĉefan tablon denaske. La kreado de nova sekcio daŭre estas lasita al la konscienco de la aplikaĵo.

"Segi" vortarojn

Kiel en iu ajn analiza sistemo, ni ankaŭ havis "faktoj" kaj "tranĉoj" (vortaroj). En nia kazo, en ĉi tiu kapablo ili agis, ekzemple, ŝablona korpo similaj malrapidaj demandoj aŭ la teksto de la demando mem.

"Faktoj" estis sekciitaj tage jam delonge, do ni trankvile forigis malnoviĝintajn sekciojn, kaj ili ne ĝenis nin (protokoloj!). Sed estis problemo pri vortaroj...

Por ne diri, ke ili estis multaj, sed proksimume 100TB da "faktoj" rezultigis 2.5TB vortaron. Vi ne povas oportune forigi ion el tia tabelo, vi ne povas kunpremi ĝin en taŭga tempo, kaj skribi al ĝi iom post iom malrapidiĝis.

Kiel vortaro... en ĝi, ĉiu enskribo estu prezentita ekzakte unufoje... kaj ĉi tio estas ĝusta, sed!.. Neniu malhelpas nin havi aparta vortaro por ĉiu tago! Jes, ĉi tio alportas certan redundon, sed ĝi permesas:

  • skribi/legi pli rapide pro pli malgranda sekcia grandeco
  • konsumu malpli da memoro laborante kun pli kompaktaj indeksoj
  • stoki malpli da datumoj pro la kapablo rapide forigi malmodernajn

Kiel rezulto de la tuta komplekso de mezuroj CPU-ŝarĝo malpliiĝis je ~30%, diskŝarĝo je ~50%:

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB
Samtempe, ni daŭre skribis ĝuste la samon en la datumbazon, nur kun malpli da ŝarĝo.

#2. Evoluo kaj refactoring de datumbazoj

Do ni decidis pri tio, kion ni havas ĉiu tago havas sian propran sekcion kun datumoj. Fakte, CHECK (dt = '2018-10-12'::date) — kaj estas dispartiga ŝlosilo kaj la kondiĉo por ke rekordo falu en specifan sekcion.

Ĉar ĉiuj raportoj en nia servo estas konstruitaj en la kunteksto de specifa dato, la indeksoj por ili ekde "ne-dispartitaj tempoj" estis ĉiuj specoj. (Servilo, Dato, Planŝablono), (Servilo, Dato, Plana nodo), (Dato, Erara klaso, Servilo)...

Sed nun ili vivas sur ĉiu sekcio viajn kopiojn ĉiu tia indekso... Kaj ene de ĉiu sekcio dato estas konstanto... Montriĝas, ke nun ni estas en ĉiu tia indekso simple enigu konstanton kiel unu el la kampoj, kiu pliigas kaj sian volumenon kaj la serĉtempon por ĝi, sed ne alportas ajnan rezulton. Ili lasis la rastilon al si mem, ho...

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB
La direkto de optimumigo estas evidenta - simpla forigu la datkampon el ĉiuj indeksoj sur dividitaj tabloj. Konsiderante niajn volumojn, la gajno estas proksimume 1TB/semajno!

Nun ni notu, ke ĉi tiu terabajto ankoraŭ devis esti registrita iel. Tio estas, ankaŭ ni la disko nun devus ŝargi malpli! Ĉi tiu bildo klare montras la efikon akiritan de la purigado, al kiu ni dediĉis semajnon:

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB

#3. "Disvastigi" la pintan ŝarĝon

Unu el la grandaj problemoj de ŝarĝitaj sistemoj estas redunda sinkronigo iuj operacioj kiuj ne postulas ĝin. Foje "ĉar ili ne rimarkis", foje "estis pli facile tiel", sed baldaŭ aŭ malfrue oni devas forigi ĝin.

Ni zomu al la antaŭa bildo kaj vidu, ke ni havas diskon "pumpis" sub la ŝarĝo kun duobla amplitudo inter apudaj specimenoj, kio klare "statistike" ne devus okazi kun tia nombro da operacioj:

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB

Ĉi tio estas sufiĉe facile atingi. Ni jam komencis monitoradon preskaŭ 1000 serviloj, ĉiu estas prilaborita per aparta logika fadeno, kaj ĉiu fadeno restarigas la amasigitan informon por esti sendita al la datumbazo je certa frekvenco, io kiel ĉi tio:

setInterval(sendToDB, interval)

La problemo ĉi tie kuŝas ĝuste en tio, ke ĉiuj fadenoj komenciĝas proksimume samtempe, do iliaj sendotempoj preskaŭ ĉiam koincidas "ĝis la punkto." Ho numero 2...

Feliĉe, ĉi tio estas sufiĉe facile ripari, aldonante "hazardan" pliiĝon laŭ tempo:

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

#4. Ni konservas tion, kion ni bezonas

La tria tradicia altŝarĝa problemo estas neniu kaŝmemoro kie li estas povus esti.

Ekzemple, ni ebligis analizi laŭ plannodoj (ĉiuj ĉi Seq Scan on users), sed tuj pensu, ke ili estas plejparte samaj - ili forgesis.

Ne, kompreneble, nenio estas skribita al la datumbazo denove, ĉi tio tranĉas la ellasilon kun INSERT ... ON CONFLICT DO NOTHING. Sed ĉi tiuj datumoj ankoraŭ atingas la datumbazon, kaj ĝi estas nenecesa legado por kontroli konflikton devas fari. Ho numero 3...

La diferenco en la nombro da rekordoj senditaj al la datumbazo antaŭ/post kiam la kaŝmemoro estas ebligita estas evidenta:

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB

Kaj jen la akompana falo en stokada ŝarĝo:

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB

Tuta

"Terabajto-po-tago" nur sonas timiga. Se vi faras ĉion ĝuste, tiam ĉi tio estas nur 2^40 bajtoj / 86400 sekundoj = ~12.5MB/ske eĉ labortablaj IDE-ŝraŭboj tenis. 🙂

Sed serioze, eĉ kun dekobla "dekliniĝo" de la ŝarĝo dum la tago, vi povas facile renkonti la kapablojn de modernaj SSD-oj.

Ni skribas en PostgreSQL pri sublumo: 1 gastiganto, 1 tago, 1TB

fonto: www.habr.com

Aldoni komenton