Kami nyerat dina PostgreSQL dina sublight: 1 host, 1 dinten, 1TB
Anyar-anyar ieu kuring nyarioskeun ka anjeun kumaha, nganggo resep standar ningkatkeun kinerja SQL maca queries ti database PostgreSQL. Dinten ieu kami bakal ngobrol ngeunaan kumaha ngarékam bisa dilakukeun leuwih éfisién dina pangkalan data tanpa nganggo "pulas" dina config - cukup ku leres ngatur aliran data.
Mimitina, sapertos MVP mana waé, proyék kami dimimitian dina beban anu lumayan - ngawaskeun ngan ukur pikeun sapuluh server anu paling kritis, sadaya tabel rélatif kompak ... , sarta sakali deui urang diusahakeun ngalakukeun hiji hal kalawan salah sahiji tabél 1.5TB ukuranana, urang sadar yén sanajan éta bisa neruskeun hirup kawas ieu, éta pisan pikaresepeun.
Waktu éta ampir kawas jaman epik, versi béda tina PostgreSQL 9.x éta relevan, jadi sagala partisi kudu dipigawé "sacara manual" - ngaliwatan warisan tabel sarta micu routing kalawan dinamis EXECUTE.
Solusi anu dihasilkeun tétéla cukup universal anu tiasa ditarjamahkeun kana sadaya tabel:
Hiji kosong "header" tabel indungna dinyatakeun, nu digambarkeun sadayana indéks diperlukeun tur micu.
Catetan tina sudut pandang klien dilakukeun dina tabel "root", sareng nganggo internal routing pemicuBEFORE INSERT catetan ieu "fisik" diselapkeun kana bagian diperlukeun. Upami teu acan aya anu sapertos kitu, urang mendakan pengecualian sareng ...
… ku ngagunakeun CREATE TABLE ... (LIKE ... INCLUDING ...) dijieun dumasar kana citakan tabel indungna bagian kalawan pangwatesan dina tanggal dipikahoyongku kituna lamun data dipulut, bacaan dipigawé ngan di dinya.
PG10: usaha munggaran
Tapi ngabagi warisan sacara sajarahna henteu cocog pikeun ngatur aliran nulis aktip atanapi sajumlah ageung partisi anak. Contona, Anjeun bisa ngelingan yen algoritma pikeun milih bagian diperlukeun tadi pajeulitna kuadrat, yén éta tiasa dianggo sareng 100+ bagian, anjeun nyalira ngartos kumaha...
Dina PG10 kaayaan ieu greatly dioptimalkeun ku ngalaksanakeun rojongan partitioning pribumi. Ku alatan éta, urang langsung nyoba nerapkeun eta langsung saatos migrasi gudang, tapi ...
Sakumaha anu kabuktian saatos ngagali manual, tabel partisi asli dina versi ieu nyaéta:
teu ngarojong déskripsi indéks
teu ngarojong pemicu dina eta
teu tiasa janten "turunan" saha waé
teu ngarojong INSERT ... ON CONFLICT
teu bisa ngahasilkeun bagian otomatis
Sanggeus narima niup nyeri kana dahi kalawan rake a, urang sadar yén éta bakal mungkin mun ngalakukeun tanpa ngaropéa aplikasi, sarta ditunda panalungtikan salajengna salila genep bulan.
PG10: kasempetan kadua
Janten, urang mimitian ngarengsekeun masalah anu timbul hiji-hiji:
Kusabab micu na ON CONFLICT Kami mendakan yén kami masih peryogi aranjeunna di ditu di dieu, janten kami ngadamel tahap panengah pikeun ngagarap aranjeunna méja proxy.
Ngaleungitkeun "ruteu" dina micu - nyaeta, ti EXECUTE.
Aranjeunna nyandak kaluar nyalira tabel template kalawan sagala indéksambéh maranéhanana henteu malah hadir dina tabel proxy.
Tungtungna, saatos sadayana ieu, urang ngabagi tabel utama sacara asli. Nyiptakeun bagian anyar masih ditinggalkeun ka nurani aplikasi.
Kamus "Sawing".
Sapertos dina sistem analitis naon waé, kami ogé ngagaduhan "fakta" sareng "potongan" (kamus). Dina hal urang, dina kapasitas ieu aranjeunna acted, contona, awak template queries slow sarupa atawa téks query sorangan.
"Fakta" parantos dipisahkeun sadinten kanggo waktos anu lami, janten kami ngahapus bagian anu luntur, sareng aranjeunna henteu ngaganggu kami (log!). Tapi aya masalah sareng kamus ...
Teu disebutkeun yen aya loba di antarana, tapi kira-kira 100TB "fakta" ngahasilkeun kamus 2.5TB. Anjeun teu tiasa ngahapus nanaon tina méja sapertos kitu, anjeun moal tiasa ngompres dina waktos anu cekap, sareng nyerat kana éta laun janten langkung laun.
Siga kamus... di dinya, unggal entri kudu dibere persis sakali ... jeung ieu bener, tapi! kamus misah pikeun unggal poé! Leres, ieu nyababkeun redundansi anu tangtu, tapi ngamungkinkeun:
nulis / maca leuwih gancang alatan ukuran bagian leutik
meakeun memori kirang ku gawé bareng indéks langkung kompak
nyimpen data kirang alatan kamampuhan pikeun gancang nyabut tinggaleun jaman
Salaku hasil tina sakabeh kompléks ukuran Beban CPU turun ku ~30%, beban disk ku ~50%:
Dina waktu nu sarua, urang terus nulis persis hal anu sarua kana database, ngan kalawan beban kirang.
#2. Évolusi database sareng refactoring
Janten urang netepkeun naon anu urang gaduh unggal poé boga bagian sorangan kalawan data. Sabenerna, CHECK (dt = '2018-10-12'::date) - tur aya hiji konci partisi jeung kaayaan pikeun rékaman digolongkeun kana bagian husus.
Kusabab sadaya laporan dina jasa kami diwangun dina kontéks tanggal anu spesifik, indéks pikeun aranjeunna ti saprak "jaman anu henteu dipisahkeun" mangrupikeun sagala jinis. (Server, tanggal, Citakan Rencana), (Server, tanggal, titik rencana), (tanggal, Kelas kasalahan, Server)...
Tapi ayeuna aranjeunna hirup dina unggal bagian salinan Anjeun unggal indéks sapertos ... Sarta dina unggal bagian tanggal nyaéta konstanta... Tétéla ayeuna urang aya dina unggal indéks misalna saukur ngasupkeun konstanta salaku salah sahiji widang, nu ngaronjatkeun duanana volume sarta waktu pilarian pikeun eta, tapi teu mawa hasil nanaon. Aranjeunna ninggalkeun rake sorangan, aduh...
Arah optimasi atra - basajan miceun widang tanggal tina sagala indéks dina tabel partitioned. Dibikeun jilid kami, gain nyaeta ngeunaan 1TB/minggu!
Ayeuna hayu urang perhatikeun yén terabyte ieu masih kedah dirékam kumaha waé. Nyaeta, urang ogé disk ayeuna kedah beban kirang! Gambar ieu jelas nunjukkeun pangaruh anu dicandak tina beberesih, anu kami bakti saminggu:
#3. "Nyebarkeun" beban puncak
Salah sahiji troubles badag sistem dimuat nyaéta sinkronisasi kaleuleuwihan sababaraha operasi anu teu merlukeun eta. Kadang-kadang "kusabab teu aya bewara", sakapeung "éta gampang cara éta", tapi sooner atanapi engké anjeun kudu meunang leupas tina eta.
Hayu urang ngazum gede dina gambar saméméhna tur tingal yen urang boga disk "pompa" handapeun beban kalayan amplitudo ganda antara sampel padeukeut, nu jelas "statistik" teu kudu lumangsung kalawan sababaraha operasi:
Ieu rada gampang pikeun ngahontal. Kami parantos ngamimitian ngawaskeun ampir 1000 server, masing-masing diolah ku benang logis anu misah, sareng unggal benang ngareset inpormasi akumulasi pikeun dikirim ka pangkalan data dina frékuénsi anu tangtu, sapertos kieu:
setInterval(sendToDB, interval)
Masalahna di dieu perenahna persis dina kanyataan yén kabéh threads dimimitian dina waktu nu sarua, jadi waktu ngirimna ampir sok coincide "to the point". Aduh #2...
Untungna, ieu rada gampang pikeun ngalereskeun, nambahkeun hiji "acak" ngajalankeun-up ku waktos:
Masalah highload tradisional katilu nyaéta euweuh cache dimana anjeunna bisa janten.
Salaku conto, kami ngamungkinkeun pikeun nganalisis tina segi titik rencana (sadayana ieu Seq Scan on users), tapi langsung mikir yén aranjeunna, sabagéan ageung, sami - aranjeunna hilap.
Taya, tangtosna, nanaon geus ditulis kana database deui, ieu motong kaluar pemicu kalawan INSERT ... ON CONFLICT DO NOTHING. Tapi data ieu masih ngahontal database, sarta éta teu perlu maca pikeun mariksa konflik kudu ngalakukeun. Aduh #3...
Bédana dina jumlah rékaman anu dikirim ka pangkalan data sateuacan / saatos cache diaktipkeun jelas:
Sareng ieu mangrupikeun turunna beban panyimpenan:
dina total
"Terabyte-per-day" ngan disada pikasieuneun. Upami anjeun ngalakukeun sadayana leres, maka éta waé 2^40 bait / 86400 detik = ~12.5MB/séta malah screws IDE desktop dicekel. 🙂
Tapi serius, sanajan kalawan sapuluh kali "skew" beban salila poé, anjeun bisa kalayan gampang minuhan kamampuhan SSDs modern.