ProHoster > Blog > İdarə > PostgreSQL-də sublight üzərində yazırıq: 1 host, 1 gün, 1TB
PostgreSQL-də sublight üzərində yazırıq: 1 host, 1 gün, 1TB
Bu yaxınlarda standart reseptlərdən istifadə edərək necə dedim SQL oxu sorğularının performansını artırmaq PostgreSQL verilənlər bazasından. Bu gün biz necə danışacağıq qeyd daha səmərəli həyata keçirilə bilər konfiqurasiyada heç bir “twist” istifadə etmədən verilənlər bazasında - sadəcə məlumat axınını düzgün təşkil etməklə.
Əvvəlcə, hər hansı bir MVP kimi, layihəmiz də kifayət qədər yüngül yük altında başladı - monitorinq yalnız on ən kritik server üçün həyata keçirildi, bütün cədvəllər nisbətən yığcam idi... Lakin zaman keçdikcə monitorinq edilən hostların sayı getdikcə artdı. , və bir daha onlardan biri ilə nəsə etməyə çalışdıq 1.5 TB ölçüsündə masalar, anladıq ki, belə yaşamağa davam etmək mümkün olsa da, çox əlverişsizdir.
Dövrlər demək olar ki, epik dövrlərə bənzəyirdi, PostgreSQL 9.x-in müxtəlif versiyaları aktual idi, buna görə də bütün bölmələr "əl ilə" aparılmalı idi. cədvəlin mirası və tetikleyiciler dinamik ilə marşrutlaşdırma EXECUTE.
Nəticədə həll o qədər universal oldu ki, bütün cədvəllərə tərcümə oluna bilsin:
Hamısını təsvir edən boş "başlıq" ana cədvəli elan edildi zəruri göstəricilər və tetikler.
Müştərinin nöqteyi-nəzərindən qeyd “kök” cədvəlində və daxili istifadə ilə aparılmışdır marşrutlaşdırma tetikleyicisiBEFORE INSERT qeyd tələb olunan bölməyə “fiziki olaraq” daxil edilmişdir. Hələ belə bir şey yox idisə, biz bir istisna tutduq və...
… istifadə etməklə CREATE TABLE ... (LIKE ... INCLUDING ...) ana cədvəlin şablonu əsasında yaradılmışdır istədiyiniz tarixə məhdudiyyət qoyulmuş bölməbelə ki, məlumatlar əldə edildikdə oxu yalnız onda həyata keçirilir.
PG10: ilk cəhd
Lakin miras yolu ilə bölmə tarixən aktiv yazma axını və ya çoxlu sayda uşaq bölmələri ilə işləmək üçün uyğun olmayıb. Məsələn, tələb olunan bölməni seçmək üçün alqoritmin olduğunu xatırlaya bilərsiniz kvadratik mürəkkəblik, 100+ bölmə ilə işlədiyini, özünüz necə başa düşürsünüz...
PG10-da bu vəziyyət dəstəyi həyata keçirməklə çox optimallaşdırıldı yerli bölmə. Buna görə anbarı köçürdükdən dərhal sonra dərhal tətbiq etməyə çalışdıq, lakin...
Təlimatı araşdırdıqdan sonra məlum oldu ki, bu versiyada yerli olaraq bölünmüş cədvəl:
indeks təsvirlərini dəstəkləmir
üzərindəki tətikləri dəstəkləmir
heç kimin “nəsli” ola bilməz
dəstəkləməyin INSERT ... ON CONFLICT
bölməni avtomatik yarada bilməz
Dırmıq ilə alnına ağrılı bir zərbə aldıqdan sonra tətbiqi dəyişdirmədən bunu etməyin mümkün olmadığını başa düşdük və sonrakı araşdırmaları altı aya təxirə saldıq.
PG10: ikinci şans
Beləliklə, ortaya çıxan problemləri bir-bir həll etməyə başladıq:
Çünki tetikler və ON CONFLICT Biz onlara hələ də burada və orada ehtiyacımız olduğunu gördük, buna görə də onları işləmək üçün aralıq mərhələ etdik proxy cədvəli.
"marşrutlaşdırma" dan xilas oldum tetikleyicilerde - yəni EXECUTE.
Ayrı-ayrılıqda çıxarıblar bütün indeksləri olan şablon cədvəlibelə ki, onlar hətta proxy cədvəlində mövcud deyillər.
Nəhayət, bütün bunlardan sonra biz əsas cədvəli yerli olaraq böldük. Yeni bölmənin yaradılması hələ də tətbiqin vicdanına qalıb.
"mişar" lüğətləri
İstənilən analitik sistemdə olduğu kimi, bizdə də var idi "faktlar" və "kəsiklər" (lüğətlər). Bizim vəziyyətimizdə, bu vəzifədə, məsələn, şablon gövdəsi oxşar yavaş sorğular və ya sorğunun mətni.
"Faktlar" artıq uzun müddətdir ki, gündən-günə bölünürdü, buna görə də köhnəlmiş bölmələri sakitcə sildik və onlar bizi narahat etmədi (loglar!). Amma lüğətlərdə problem var idi...
Onların çox olduğunu söyləməyək, amma təxminən 100 TB "fakt" 2.5 TB lüğət ilə nəticələndi. Belə bir cədvəldən heç bir şeyi rahatlıqla silə bilməzsiniz, onu lazımi vaxtda sıxışdıra bilməzsiniz və ona yazmaq getdikcə yavaşladı.
Lüğət kimi... orada hər giriş düz bir dəfə təqdim edilməlidir... və bu düzgündür, amma!.. Bizə heç kim mane olmur. hər gün üçün ayrıca lüğət! Bəli, bu müəyyən bir artıqlıq gətirir, lakin imkan verir:
daha sürətli yaz/oxu daha kiçik bölmə ölçüsünə görə
daha az yaddaş istehlak edir daha yığcam indekslərlə işləməklə
daha az məlumat saxlamaq köhnəlmişləri tez aradan qaldırmaq qabiliyyətinə görə
Bütün kompleks tədbirlər nəticəsində CPU yükü ~30%, disk yükü ~50% azalıb:
Eyni zamanda, biz daha az yüklə verilənlər bazasına tam olaraq eyni şeyi yazmağa davam etdik.
#2. Verilənlər bazasının təkamülü və refaktorinqi
Beləliklə, əlimizdə olanlara qərar verdik hər günün öz bölməsi var data ilə. Əslində, CHECK (dt = '2018-10-12'::date) — və bölmə açarı və qeydin müəyyən bir bölməyə düşməsi şərti var.
Xidmətimizdəki bütün hesabatlar müəyyən bir tarix kontekstində qurulduğundan, "bölünməmiş vaxtlardan" bəri onlar üçün indekslər bütün növlər olmuşdur. (Server, Tarix, Plan Şablonu), (Server, Tarix, Plan node), (Tarix, Xəta sinfi, Server)...
Amma indi hər bölmədə yaşayırlar nüsxələriniz hər bir belə indeks... Və hər bölmə daxilində tarix sabitdir... Belə çıxır ki, indi biz hər bir belə indeksdəyik sadəcə bir sabit daxil edin həm həcmini, həm də onun üçün axtarış vaxtını artıran, lakin heç bir nəticə verməyən sahələrdən biri kimi. Dırmığı özlərinə buraxdılar, ay...
Optimallaşdırma istiqaməti aydındır - sadədir tarix sahəsini bütün indekslərdən çıxarın bölünmüş masalarda. Həcmimizi nəzərə alsaq, qazanc təxminəndir 1TB/həftə!
İndi qeyd edək ki, bu terabayt hələ də hansısa yolla qeydə alınmalı idi. Yəni biz də disk indi daha az yüklənməlidir! Bu şəkil bir həftə həsr etdiyimiz təmizlikdən əldə edilən effekti aydın şəkildə göstərir:
#3. Pik yükün "yayılması"
Yüklənmiş sistemlərin ən böyük problemlərindən biri də budur lazımsız sinxronizasiya tələb etməyən bəzi əməliyyatlar. Bəzən “diqqət etmədikləri üçün”, bəzən “belə daha asan idi”, amma gec-tez ondan qurtulmalısan.
Gəlin əvvəlki şəkli böyüdək və görək diskimiz var İkiqat amplituda ilə yük altında "nasoslar" bitişik nümunələr arasında, belə bir sıra əməliyyatlarla aydın şəkildə "statistik olaraq" baş verməməlidir:
Buna nail olmaq olduqca asandır. Artıq monitorinqlərə başlamışıq təxminən 1000 server, hər biri ayrıca bir məntiqi ip tərəfindən işlənir və hər bir ip müəyyən bir tezlikdə verilənlər bazasına göndəriləcək yığılmış məlumatı sıfırlayır, buna bənzər bir şey:
setInterval(sendToDB, interval)
Burada problem məhz ondadır bütün mövzular təxminən eyni vaxtda başlayır, buna görə də onların göndərilmə vaxtları demək olar ki, həmişə "nöqtəsinə" uyğun gəlir. Vay #2...
Xoşbəxtlikdən, bunu düzəltmək olduqca asandır, "təsadüfi" bir qaçış əlavə edin vaxta görə:
Üçüncü ənənəvi yüklənmə problemidir önbellek yoxdur o haradadır bilərdi olmaq.
Məsələn, plan qovşaqları baxımından təhlil etməyə imkan verdik (bütün bunlar Seq Scan on users), amma dərhal fikirləşin ki, onlar əksər hallarda eynidirlər - unutdular.
Xeyr, əlbəttə ki, verilənlər bazasına yenidən heç bir şey yazılmır, bu, tətiyi kəsir INSERT ... ON CONFLICT DO NOTHING. Lakin bu məlumatlar hələ də verilənlər bazasına çatır və bu, lazımsızdır ziddiyyəti yoxlamaq üçün oxuyun etməli. Vay #3...
Keşləmə işə salınmazdan əvvəl/sonra verilənlər bazasına göndərilən qeydlərin sayındakı fərq göz qabağındadır:
Bu saxlama yükünün müşayiət olunan azalmasıdır:
Ümumi
“Gündə terabayt” sadəcə qorxulu səslənir. Əgər hər şeyi düzgün etsəniz, deməli bu sadəcə 2^40 bayt / 86400 saniyə = ~12.5MB/ski, hətta masa üstü IDE vintlər keçirilir. 🙂
Ancaq ciddi şəkildə, gün ərzində yükün on qat "çarpması" ilə belə, müasir SSD-lərin imkanlarını asanlıqla qarşılaya bilərsiniz.