Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB

Geçenlerde size standart tarifleri kullanarak nasıl yapılacağını anlattım SQL okuma sorgularının performansını artırın PostgreSQL veritabanından. Bugün bunun nasıl yapılacağı hakkında konuşacağız kayıt daha verimli yapılabilir yapılandırmada herhangi bir "bükülme" kullanmadan veritabanında - yalnızca veri akışlarını doğru şekilde düzenleyerek.

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB

#1. Bölümleme

Nasıl ve neden organize edilmeye değer olduğuna dair bir makale uygulamalı bölümleme “teoride” zaten olmuştur, burada bazı yaklaşımların uygulama pratiğinden bahsedeceğiz. Yüzlerce PostgreSQL sunucusu için izleme hizmeti.

"Geçmişte olan şeyler..."

Başlangıçta, tüm MVP'ler gibi projemiz de oldukça hafif bir yük altında başladı; izleme yalnızca en kritik on sunucu için gerçekleştirildi, tüm tablolar nispeten kompakttı... Ancak zaman geçtikçe izlenen ana bilgisayarların sayısı giderek arttı ve bir kez daha şunlardan biriyle bir şeyler yapmaya çalıştık: 1.5 TB boyutunda tablolar, bu şekilde yaşamaya devam etmenin mümkün olmasına rağmen bunun çok sakıncalı olduğunu anladık.

Zamanlar neredeyse epik zamanlardı, PostgreSQL 9.x'in farklı sürümleri geçerliydi, bu nedenle tüm bölümlemenin "manuel" olarak yapılması gerekiyordu. tablo mirası ve tetikleyiciler dinamik yönlendirme EXECUTE.

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB
Ortaya çıkan çözümün tüm tablolara çevrilebilecek kadar evrensel olduğu ortaya çıktı:

  • Tüm bunları açıklayan boş bir "başlık" ana tablosu bildirildi. gerekli indeksler ve tetikleyiciler.
  • Müşterinin bakış açısından kayıt "kök" tabloda ve dahili olarak kullanılarak yapıldı. yönlendirme tetikleyicisi BEFORE INSERT kayıt gerekli bölüme “fiziksel olarak” yerleştirildi. Eğer henüz böyle bir şey olmadıysa, bir istisna yakaladık ve...
  • … kullanarak CREATE TABLE ... (LIKE ... INCLUDING ...) ana tablonun şablonu temel alınarak oluşturuldu İstenilen tarihte kısıtlama olan bölümböylece veri alındığında okuma yalnızca veride gerçekleştirilir.

PG10: ilk deneme

Ancak kalıtım yoluyla bölümleme, tarihsel olarak aktif bir yazma akışıyla veya çok sayıda alt bölümle başa çıkmak için pek uygun değildi. Örneğin, gerekli bölümün seçilmesine yönelik algoritmanın sahip olduğunu hatırlayabilirsiniz. ikinci dereceden karmaşıklık100'den fazla bölümle çalıştığını kendiniz anlıyorsunuz...

PG10'da bu durum destek uygulanarak büyük ölçüde optimize edildi yerel bölümleme. Bu nedenle, depolamayı taşıdıktan hemen sonra hemen uygulamaya çalıştık, ancak...

Kılavuzu inceledikten sonra ortaya çıktığı gibi, bu sürümdeki yerel olarak bölümlendirilmiş tablo şöyledir:

  • dizin açıklamalarını desteklemiyor
  • üzerindeki tetikleyicileri desteklemiyor
  • kimsenin “torunu” olamaz
  • desteklemiyor INSERT ... ON CONFLICT
  • otomatik olarak bölüm oluşturulamıyor

Alnımıza tırmıkla acı veren bir darbe aldıktan sonra, uygulamayı değiştirmeden yapmanın imkansız olacağını anladık ve daha fazla araştırmayı altı ay erteledik.

PG10: ikinci şans

Böylece ortaya çıkan sorunları tek tek çözmeye başladık:

  1. Çünkü tetikleyiciler ve ON CONFLICT Onlara hâlâ orada burada ihtiyacımız olduğunu gördük ve bunları çözmek için bir ara aşama oluşturduk. vekil tablo.
  2. "Yönlendirmeden" kurtuldum tetikleyicilerde - yani, EXECUTE.
  3. Ayrı ayrı çıkardılar tüm dizinleri içeren şablon tablosuböylece proxy tablosunda bile mevcut değiller.

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB
Son olarak tüm bunlardan sonra ana tabloyu native olarak bölümlendirdik. Yeni bir bölümün oluşturulması hâlâ uygulamanın vicdanına bırakılmıştır.

“Testere” sözlükleri

Herhangi bir analitik sistemde olduğu gibi, aynı zamanda "gerçekler" ve "kesintiler" (sözlükler). Bizim durumumuzda bu sıfatla hareket ettiler, örneğin: şablon gövdesi benzer yavaş sorgular veya sorgunun metni.

"Gerçekler" uzun süredir günlere göre bölümlere ayrılmıştı, bu nedenle güncel olmayan bölümleri sakince sildik ve bunlar bizi rahatsız etmedi (günlükler!). Ama sözlüklerde bir sorun vardı...

Birçoğunun olduğunu söylemiyorum ama yaklaşık olarak 100 TB'lık "gerçekler", 2.5 TB'lık bir sözlükle sonuçlandı. Böyle bir tablodan hiçbir şeyi rahatça silemezsiniz, yeterli sürede sıkıştıramazsınız ve tabloya yazmak giderek yavaşladı.

Sözlük gibi... İçinde her girdi tam olarak bir kez sunulmalı... Bu da doğru ama!.. Kimse bizi bu konudan alıkoyamıyor. her gün için ayrı bir sözlük! Evet, bu belirli bir fazlalık getirir ancak şunları sağlar:

  • daha hızlı yazma/okuma daha küçük bölüm boyutu nedeniyle
  • daha az bellek tüketin daha kompakt dizinlerle çalışarak
  • daha az veri depola güncelliğini hızla kaldırabilme yeteneği nedeniyle

Tüm önlemler kompleksinin bir sonucu olarak CPU yükü ~%30, disk yükü ~%50 azaldı:

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB
Aynı zamanda, daha az yükle tamamen aynı şeyi veritabanına yazmaya devam ettik.

#2. Veritabanı gelişimi ve yeniden düzenleme

Bu yüzden sahip olduklarımıza karar verdik her günün kendi bölümü vardır verilerle. Aslında, CHECK (dt = '2018-10-12'::date) — ve bir bölümleme anahtarı ve bir kaydın belirli bir bölüme düşmesi koşulu vardır.

Hizmetimizdeki tüm raporlar belirli bir tarih bağlamında oluşturulduğundan, "bölümlendirilmemiş zamanlar"dan bu yana bunlara ilişkin dizinler her türden olmuştur. (Sunucu, Tarih, Plan Şablonu), (Sunucu, Tarih, Plan düğümü), (Tarih, Hata sınıfı, Sunucu), ...

Ama şimdi her bölümde yaşıyorlar kopyalarınız bu tür dizinlerin her biri... Ve her bölümün içinde tarih bir sabittir... Görünüşe göre artık bu tür indekslerin her birindeyiz sadece bir sabit girin hem hacmini hem de arama süresini artıran ancak sonuç getirmeyen alanlardan biri olarak. Tırmığı kendilerine bırakmışlar, ah...

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB
Optimizasyon yönü açıktır - basit tarih alanını tüm dizinlerden kaldır bölümlenmiş tablolarda. Hacimlerimiz göz önüne alındığında, kazanç yaklaşık 1TB/hafta!

Şimdi bu terabaytın hala bir şekilde kaydedilmesi gerektiğini not edelim. Yani biz de disk artık daha az yüklenmeli! Bu resim, bir haftayı adadığımız temizliğin etkisini açıkça gösteriyor:

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB

#3. Pik yükün “yayılması”

Yüklü sistemlerin en büyük sorunlarından biri yedek senkronizasyon gerektirmeyen bazı işlemler. Bazen “fark etmedikleri için”, bazen “böylesi daha kolaydı” ama er ya da geç ondan kurtulmak zorundasın.

Önceki resme yakınlaşalım ve bir diskimizin olduğunu görelim yük altında çift genlikli “pompalar” "istatistiksel olarak" açıkça bu kadar çok sayıda işlemle gerçekleşmemesi gereken bitişik örnekler arasında:

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB

Bunu başarmak oldukça kolaydır. İzlemeye çoktan başladık neredeyse 1000 sunucu, her biri ayrı bir mantıksal iş parçacığı tarafından işlenir ve her iş parçacığı, veritabanına gönderilecek olan birikmiş bilgileri belirli bir sıklıkta sıfırlar, bunun gibi bir şey:

setInterval(sendToDB, interval)

Buradaki sorun tam olarak şu gerçeğin ortaya çıkmasında yatmaktadır: tüm ileti dizileri yaklaşık olarak aynı anda başlar, dolayısıyla gönderme süreleri neredeyse her zaman "asıl noktaya" denk gelir. Eyvah #2...

Neyse ki bunu düzeltmek oldukça kolaydır, “rastgele” bir koşu ekleme zamanla:

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

#4. İhtiyacımız olanı önbelleğe alıyoruz

Üçüncü geleneksel aşırı yük sorunu önbellek yok o nerede could olmak için.

Mesela plan düğümleri açısından analiz yapmayı mümkün kıldık (tüm bunlar Seq Scan on users), ama hemen bunların çoğunlukla aynı olduğunu düşünün - unuttular.

Hayır tabi ki yine veritabanına hiçbir şey yazılmıyor, bu durum tetikleyiciyi kesiyor INSERT ... ON CONFLICT DO NOTHING. Ancak bu veriler yine de veritabanına ulaşıyor ve gereksiz Çatışmayı kontrol etmek için okuma yapmalı. Eyvah #3...

Önbelleğe alma etkinleştirilmeden önce/sonra veritabanına gönderilen kayıtların sayısındaki fark açıktır:

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB

Bu da depolama yükünde beraberinde gelen düşüş:

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB

Toplam

"Günde terabayt" kulağa korkutucu geliyor. Her şeyi doğru yaparsanız, bu sadece 2^40 bayt / 86400 saniye = ~12.5MB/smasaüstü IDE vidaları bile tutuyordu. 🙂

Ancak cidden, gün içindeki yükün on kat "çarpık" olmasına rağmen, modern SSD'lerin yeteneklerini kolayca karşılayabilirsiniz.

Sublight'ta PostgreSQL'de yazıyoruz: 1 ana bilgisayar, 1 gün, 1 TB

Kaynak: habr.com

Yorum ekle