PostgreSQL-n idazten dugu azpiargia: 1 host, 1 day, 1TB
Duela gutxi kontatu dizut nola, errezeta estandarrak erabiliz SQL irakurketa kontsulten errendimendua handitu PostgreSQL datu-basetik. Gaur nola hitz egingo dugu grabaketa modu eraginkorragoan egin daiteke datu-basean konfigurazioan "bira"rik erabili gabe, datu-fluxuak behar bezala antolatuz.
Hasieran, edozein MVP bezala, gure proiektua nahiko karga arinean hasi zen - monitorizazioa hamar zerbitzari kritikoenentzat bakarrik egiten zen, mahai guztiak nahiko trinkoak ziren... Baina denborak aurrera egin ahala, monitorizatutako ostalarien kopurua gero eta handiagoa zen. , eta beste behin saiatu ginen zerbait egiten batekin 1.5TBko taulak, konturatu ginen horrela bizitzen jarraitzea posible bazen ere, oso deserosoa zela.
Garaiak ia garai epikoak bezalakoak ziren, PostgreSQL 9.x-en bertsio desberdinak garrantzitsuak ziren, beraz, partizio guztiak "eskuz" egin behar ziren - bidez. taularen herentzia eta abiarazleak bideratzea dinamikoarekin EXECUTE.
Lortutako irtenbidea nahikoa unibertsala izan zen, taula guztietara itzultzeko:
"Goiburua" mahai nagusi huts bat deklaratu zen, guztiak deskribatzen zituena beharrezko indizeak eta abiarazleak.
Erregistroa bezeroaren ikuspuntutik βrootβ taulan egin zen, eta barrutik erabiliz bideratze abiarazleaBEFORE INSERT erregistroa βfisikokiβ txertatu zen eskatutako atalean. Oraindik halakorik ez bazegoen, salbuespen bat harrapatu genuen eta...
β¦ erabiliz CREATE TABLE ... (LIKE ... INCLUDING ...) guraso-taularen txantiloian oinarrituta sortu da atala nahi den dataren mugarekinberaz, datuak berreskuratzen direnean, irakurketa bertan bakarrik egiten da.
PG10: lehen saiakera
Baina herentzia bidezko partizioa ez da historikoki egokia izan idazketa korronte aktibo bati edo seme-alaba partizio kopuru handi bati aurre egiteko. Esaterako, gogoratu dezakezu eskatutako atala hautatzeko algoritmoak zuela konplexutasun koadratikoa, 100 atal baino gehiagorekin funtzionatzen duela, zuk zeuk ulertzen duzu nola...
PG10ean egoera hori asko optimizatu zen euskarria ezarriz jatorrizko zatiketa. Hori dela eta, biltegiratzea migratu ondoren berehala aplikatzen saiatu ginen, baina...
Eskuliburuan arakatu ondoren atera den bezala, bertsio honetako jatorrizko zatitutako taula hau da:
ez ditu indizeen deskribapenak onartzen
ez du abiarazlerik onartzen
ezin da inoren "ondorengoa" izan
ez onartzen INSERT ... ON CONFLICT
ezin da atal bat automatikoki sortu
Kokokian kolpe mingarria jasota arrastelarekin, aplikazioa aldatu gabe ezinezkoa izango zela konturatu ginen eta sei hilabetez atzeratu genuen ikerketa gehiago.
PG10: bigarren aukera
Beraz, banan-banan sortutako arazoak konpontzen hasi ginen:
Abiarazleak eta ON CONFLICT Han-hemenka oraindik behar genituela ikusi genuen, beraz, tarteko etapa bat egin genuen lantzeko proxy taula.
"bideratzea" kendu dut abiarazleetan - hau da, batetik EXECUTE.
Bereiz atera zuten txantiloi-taula indize guztiekinproxy taulan ere ez egon daitezen.
Azkenik, hau guztiaren ondoren, mahai nagusia modu natiboan banatu dugu. Atal berri bat sortzea oraindik aplikazioaren kontzientziaren esku geratzen da.
"Zerratu" hiztegiak
Edozein sistema analitikotan bezala, guk ere izan genuen "gertakariak" eta "mozketak" (hiztegiak). Gure kasuan, kargu horretan jardun zuten, adibidez, txantiloiaren gorputza antzeko kontsulta motelak edo kontsultaren testua bera.
"Gertaerak" egunez sekzionatuta zeuden jadanik, beraz, lasai ezabatu genituen atal zaharkituak, eta ez gintuzten molestatzen (erregistroak!). Baina arazo bat zegoen hiztegiekin...
Asko zirenik ez, gutxi gorabehera, baizik 100TB "gertaerak" 2.5TB hiztegia lortu zuen. Ezin duzu horrelako taula batetik ezer ezabatu, ezin duzu denbora egokian konprimitu eta pixkanaka idaztea moteldu egin zen.
Hiztegi bat bezala... bertan, sarrera bakoitza zehatz-mehatz behin aurkeztu behar da... eta hau zuzena da, baina!... Inork ez digu edukitzea eragozten. egun bakoitzeko hiztegi bereizia! Bai, honek nolabaiteko erredundantzia dakar, baina aukera ematen du:
idatzi/irakurtu azkarrago atalaren tamaina txikiagoa dela eta
memoria gutxiago kontsumitu indize trinkoagoekin lan eginez
datu gutxiago gordetzea zaharkitua azkar kentzeko gaitasuna dela eta
Neurri-multzo osoaren ondorioz CPUaren karga % 30 gutxitu da, eta % 50 diskoaren karga:
Aldi berean, datu-basean gauza bera idazten jarraitu genuen, karga gutxiagorekin.
#2. Datu-basearen bilakaera eta birfactorizazioa
Beraz, daukagunarekin finkatu ginen egun bakoitzak bere atala du datuekin. Egia esan, CHECK (dt = '2018-10-12'::date) β eta zatiketa-gako bat dago eta erregistro bat atal zehatz batean erortzeko baldintza dago.
Gure zerbitzuko txosten guztiak data zehatz baten testuinguruan eraikitzen direnez, "zatiketarik gabeko garai"-tik hona horien indizeak mota guztietakoak izan dira. (Zerbitzaria, Data, Plan txantiloia), (Zerbitzaria, Data, Plan nodoa), (Data, Error klasea, Zerbitzaria), ...
Baina orain atal guztietan bizi dira zure kopiak halako indize bakoitza... Eta atal bakoitzaren barruan data konstante bat da... Bihurtzen da orain indize bakoitzean gaudela konstante bat sartu besterik ez eremuetako bat bezala, bere bolumena eta bilaketa-denbora handitzen dituena, baina ez du inolako emaitzarik ekartzen. Beraiek utzi zuten arrastoa, aupa...
Optimizazioaren norabidea bistakoa da - sinplea kendu data eremua indize guztietatik zatitutako mahaietan. Gure bolumenak kontuan hartuta, irabazia ingurukoa da 1TB/astean!
Orain kontuan izan dezagun terabyte hori oraindik nolabait grabatu behar zela. Hau da, guk ere orain diskoak gutxiago kargatu beharko luke! Irudi honek garbi erakusten du aste bat eskaini genion garbiketaren ondorioz lortutako eragina:
#3. Zama gailurra "zabaltzea".
Kargatutako sistemen arazo handietako bat da sinkronizazio erredundantea eskatzen ez duten eragiketa batzuk. Batzuetan βohartu ez zirelakoβ, beste batzuetan βerrazagoa zen horrelaβ, baina lehenago edo beranduago kendu egin behar duzu.
Handitu dezagun aurreko argazkia eta ikus dezagun disko bat dugula "ponpak" karga azpian anplitude bikoitzarekin ondoko laginen artean, argi eta garbi "estatistikoki" ez litzatekeela gertatu behar horrelako eragiketekin:
Hau lortzea nahiko erraza da. Dagoeneko jarraipena egiten hasi gara ia 1000 zerbitzari, bakoitza hari logiko batek prozesatzen du, eta hari bakoitzak maiztasun jakin batean datu-basera bidali beharreko metatutako informazioa berrezartzen du, honelako zerbait:
setInterval(sendToDB, interval)
Hemen arazoa hain zuzen ere horretan datza hari guztiak gutxi gorabehera aldi berean hasten dira, beraz, bidaltzeko denborak ia beti bat datoz "punturaino". Aupa #2...
Zorionez, hau nahiko erraza da konpontzen, "ausazko" igoera bat gehituz denboraren arabera:
Karga handiko hirugarren arazo tradizionala da cacherik ez non dagoen liteke izan.
Adibidez, plan-nodoen arabera aztertzea posible egin dugu (horiek guztiak Seq Scan on users), baina berehala pentsatu, gehienetan, berdinak direla - ahaztu egin ziren.
Ez, noski, ez da ezer idazten datu-basean berriro, honek abiarazlea mozten du INSERT ... ON CONFLICT DO NOTHING. Baina datu hauek datu-basera iristen dira oraindik, eta ez dira beharrezkoak irakurtzea gatazkak egiaztatzeko egin behar. Aupa #3...
Cachea gaitu aurretik/ondoren datu-basera bidalitako erregistro-kopuruaren aldea agerikoa da:
Eta hauxe da biltegiratze-kargaren jaitsiera:
Guztira
"Terabyte-per-day"-k beldurra ematen du. Dena ondo egiten baduzu, hau besterik ez da 2^40 byte / 86400 segundo = ~12.5MB/smahaigaineko IDE torlojuak ere eutsita. π
Baina serioski, egunean zehar karga hamar aldiz "okertu" bada ere, SSD modernoen gaitasunak erraz bete ditzakezu.