Kita nulis ing PostgreSQL ing sublight: 1 host, 1 dina, 1TB
Bubar aku pitutur marang kowe carane, nggunakake resep-resep standar nambah kinerja query maca SQL saka database PostgreSQL. Dina iki kita bakal ngomong babagan carane ngrekam bisa rampung luwih irit ing basis data tanpa nggunakake "twists" ing konfigurasi - mung kanthi ngatur aliran data kanthi bener.
Kaping pisanan, kaya MVP apa wae, proyek kita diwiwiti kanthi beban sing cukup entheng - pemantauan ditindakake mung kanggo sepuluh server sing paling kritis, kabeh tabel relatif kompak ... Nanging saya suwe saya suwe, jumlah host sing dipantau dadi luwih akeh. , lan sepisan maneh kita nyoba kanggo nindakake soko karo salah siji saka Tabel ukuran 1.5TB, kita nyadari yen sanajan bisa terus urip kaya iki, nanging ora nyenengake.
Wektu meh kaya jaman epik, versi PostgreSQL 9.x sing beda-beda relevan, mula kabeh partisi kudu ditindakake "kanthi manual" - liwat pusaka Tabel lan micu routing kanthi dinamis EXECUTE.
Solusi sing diasilake dadi cukup universal supaya bisa diterjemahake menyang kabeh tabel:
Tabel induk "header" kosong diumumake, sing diterangake kabeh indeks perlu lan pemicu.
Rekaman saka sudut pandang klien digawe ing tabel "root", lan nggunakake internal routing pemicuBEFORE INSERT rekaman iki "fisik" dipasang menyang bagean dibutuhake. Yen durung ana, kita entuk pengecualian lan ...
β¦ kanthi nggunakake CREATE TABLE ... (LIKE ... INCLUDING ...) digawe adhedhasar cithakan tabel induk bagean karo watesan ing tanggal sing dikarepakesupaya nalika data dijupuk, maca mung dileksanakake ing.
PG10: nyoba pisanan
Nanging partisi liwat warisan historis ora cocog banget kanggo nggarap stream nulis aktif utawa akeh partisi turunan. Contone, sampeyan bisa kelingan sing algoritma kanggo milih bagean dibutuhake wis kompleksitas kuadrat, sing dianggo karo 100+ bagean, sampeyan dhewe ngerti carane ...
Ing PG10, kahanan iki dioptimalake kanthi nggunakake dhukungan pemisahan asli. Mulane, kita langsung nyoba aplikasi kasebut langsung sawise migrasi panyimpenan, nanging ...
Minangka ternyata sawise ngeduk manual, tabel partisi asli ing versi iki yaiku:
ora ndhukung katrangan indeks
ora ndhukung pemicu ing
ora bisa dadi "keturunan" sapa wae
ora ndhukung INSERT ... ON CONFLICT
ora bisa ngasilake bagean kanthi otomatis
Sawise nampa jotosan nglarani ing bathuk karo rake, kita temen maujud sing ora bisa kanggo nindakake tanpa ngowahi aplikasi, lan postponed riset luwih kanggo nem sasi.
PG10: kaloro kasempatan
Dadi, kita wiwit ngrampungake masalah sing muncul siji-siji:
Amarga micu lan ON CONFLICT Kita nemokake yen kita isih butuh ing kene, mula kita nggawe tahap penengah kanggo ngrampungake tabel proxy.
Ngilangi "rute" ing pemicu - sing, saka EXECUTE.
Padha njupuk metu dhewe tabel Cithakan karo kabeh indekssupaya padha ora malah ana ing meja proxy.
Pungkasan, sawise kabeh iki, kita misahake tabel utama kanthi asli. Nggawe bagean anyar isih ditinggalake ing kalbu aplikasi.
Kamus "Sawing".
Kaya ing sistem analitis, kita uga duwe "fakta" lan "potongan" (kamus). Ing kasus kita, ing kapasitas iki padha tumindak, contone, awak cithakan pitakon alon sing padha utawa teks pitakon kasebut dhewe.
Ora ngomong yen ana akeh, nanging kira-kira 100TB "fakta" ngasilake kamus 2.5TB. Sampeyan ora bisa kanthi gampang mbusak apa wae saka tabel kasebut, sampeyan ora bisa ngompres ing wektu sing cukup, lan nulis kanthi alon-alon.
Kaya kamus ... ing, saben entri kudu diwenehi persis sapisan ... lan iki bener, nanging!.. Ora ana sing ngalangi kita duwe. kamus kapisah kanggo saben dina! Ya, iki nggawa redundansi tartamtu, nanging ngidini:
nulis / maca luwih cepet amarga ukuran bagean cilik
nggunakake memori kurang kanthi nggarap indeks sing luwih kompak
nyimpen data kurang amarga kemampuan kanggo cepet mbusak outdated
Minangka asil saka kabèh Komplek saka ngukur Beban CPU suda ~30%, beban disk nganti ~50%:
Ing wektu sing padha, kita terus nulis bab sing padha menyang database, mung kanthi kurang muatan.
#2. Evolusi database lan refactoring
Dadi kita mapan ing apa sing kita duwe saben dina duwe bagean dhewe karo data. Bener, CHECK (dt = '2018-10-12'::date) - lan ana tombol pemisahan lan kondisi kanggo rekaman tiba menyang bagean tartamtu.
Amarga kabeh laporan ing layanan kita dibangun ing konteks tanggal tartamtu, indeks kanggo wong-wong mau wiwit "wektu non-partisi" wis kabeh jinis. (Server, Tanggal, Cithakan Rencana), (Server, Tanggal, Plan node), (Tanggal, Kelas kesalahan, Server)...
Nanging saiki padha manggon ing saben bagean salinan Panjenengan saben indeks kuwi... Lan ing saben bagean tanggal punika pancet... Ternyata saiki kita ana ing saben indeks kasebut mung ngetik konstanta minangka salah sawijining lapangan, sing nambah volume lan wektu telusuran, nanging ora ngasilake asil. Padha ninggalake rake kanggo awake dhewe, oops ...
Arah optimasi jelas - prasaja mbusak kolom tanggal saka kabeh indeks ing tabel partisi. Diwenehi volume kita, gain kira 1TB / minggu!
Saiki elinga yen terabyte iki isih kudu direkam. Sing, kita uga disk saiki kudu mbukak kurang! Gambar iki kanthi jelas nuduhake efek sing dipikolehi saka reresik, sing ditindakake seminggu:
#3. "Nyebar" beban puncak
Salah sawijining masalah gedhe saka sistem sing dimuat yaiku sinkronisasi keluwih sawetara operasi sing ora mbutuhake. Kadhangkala "amarga ora weruh", kadhangkala "luwih gampang kaya ngono", nanging cepet utawa mengko sampeyan kudu nyingkirake.
Ayo nggedhekake gambar sadurunge lan ndeleng manawa kita duwe disk "pompa" ing beban kanthi amplitudo ganda antarane conto jejer, kang cetha "statistik" ngirim ora kelakon karo sawetara operasi:
Iki cukup gampang kanggo entuk. Kita wis miwiti ngawasi meh 1000 server, saben diproses dening utas logis sing kapisah, lan saben utas ngreset informasi akumulasi kanggo dikirim menyang basis data kanthi frekuensi tartamtu, kaya mangkene:
setInterval(sendToDB, interval)
Masalah kene dumunung sabenere ing kasunyatan sing kabeh Utas diwiwiti ing kira-kira wektu sing padha, dadi wektu ngirim meh mesthi pas "to the point". Waduh #2...
Untunge, iki cukup gampang kanggo ndandani, nambah "acak" run-up dening wektu:
Masalah highload tradisional katelu yaiku ora cache ngendi dheweke bisa dadi
Contone, kita bisa nganalisa babagan node rencana (kabeh iki Seq Scan on users), nanging langsung mikir sing padha, kanggo sisih paling, padha - padha lali.
Ora, mesthi, ora ana sing ditulis ing database maneh, iki ngethok pemicu karo INSERT ... ON CONFLICT DO NOTHING. Nanging data iki isih tekan database, lan ora perlu maca kanggo mriksa konflik kudu nindakake. Waduh #3...
Bentenipun ing jumlah cathetan sing dikirim menyang database sadurunge / sawise caching diaktifake ketok: