1.1 Parçalama nedir?

Israrla google'da ararsanız, sözde bölümleme ile sözde parçalama arasında oldukça bulanık bir sınır olduğu ortaya çıkıyor. Herkes istediğini, istediğini çağırır. Bazı insanlar yatay bölümleme ile parçalama arasında ayrım yapar. Diğerleri, parçalamanın belirli bir tür yatay bölümleme olduğunu söylüyor.

Kurucu babalar tarafından onaylanacak ve ISO tarafından onaylanacak tek bir terminolojik standart bulamadım. Kişisel iç kanaat şöyle bir şeydir: Bölme, ortalama olarak keyfi bir şekilde “tabanı parçalara ayırmaktır”.

  • Dikey bölümleme - sütuna göre. Örneğin, 60 sütunda birkaç milyar kayıt içeren dev bir tablo var. Böyle dev bir tablo tutmak yerine, her biri 2 milyar kayıt içeren en az 60 dev tablo tutuyoruz - ve bu bir sütun tabanı değil, dikey bölümleme (terminoloji örneği olarak).
  • Yatay bölümleme - belki sunucunun içinde satır satır keseriz.

Buradaki garip an, yatay bölümleme ile parçalama arasındaki ince farktır. Parçalara ayrılabilirim ama ne olduğunu size kesin olarak söyleyemem. Parçalama ve yatay bölümlemenin aynı şey olduğu hissi var.

Parçalama , genel olarak, veritabanları açısından büyük bir tablo veya bir belge koleksiyonu, bir veritabanınız yoksa, ancak bir belge deponuz varsa, nesnelerin tam olarak nesneler tarafından kesilmesidir. Yani 2 milyar nesneden hangi boyutta olursa olsun parçalar seçilir. Her bir nesnenin içindeki nesnelerin kendileri parçalara ayrılmıyor, ayrı sütunlara yerleştirmiyoruz, yani farklı yerlere gruplar halinde yerleştiriyoruz.

İnce terminolojik farklılıklar vardır. Örneğin, nispeten konuşursak, Postgres geliştiricileri, yatay bölümlemenin, ana tablonun bölündüğü tüm tabloların aynı şemada yer aldığı ve farklı makinelerde olduğunda, bunun zaten parçalama olduğunu söyleyebilirler.

Genel anlamda, belirli bir veritabanının ve belirli bir veri yönetim sisteminin terminolojisine bağlı kalmadan, parçalamanın sadece satır satır / belge belge dilimleme olduğu hissi var ve bu böyle devam ediyor - hepsi bu.

Tipik vurguluyorum. Tüm bunları sadece 2 milyar belgeyi her biri daha yönetilebilir 20 tabloya bölmek için değil, birçok çekirdeğe, birçok diske veya birçok farklı fiziksel veya sanal sunucuya dağıtmak için yapıyoruz.

1.2 Bölünemez olanı bölün

Bunu, her parçanın - her veri parçasının - birçok kez çoğaltılması için yaptığımız anlaşılmaktadır. Ama gerçekten hayır.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

Aslında böyle bir veri dilimleme yaparsanız ve yiğit dizüstü bilgisayarınızda MySQL üzerinde dev bir SQL tablosundan, tek bir dizüstü bilgisayarın ötesine geçmeden, tek bir şema, tek bir veritabanı vb. . ve benzeri. - işte bu, zaten parçalamanız var.

Bu, aşağıdakilerle sonuçlanır:

  • Bant genişliği artar.
  • Gecikme değişmez, yani bu durumda her biri, tabiri caizse, işçi veya tüketici kendi başına alır. Farklı istekler yaklaşık olarak aynı anda karşılanır.
  • Veya her ikisi ve diğeri ve ayrıca yüksek kullanılabilirlik (çoğaltma).

Neden bant genişliği? Bazen 1 {kernel | disk | sunucu | ...}. Yeterli kaynak yok, hepsi bu. Bu büyük veri kümesiyle çalışmak için onu kesmeniz gerekir.

Neden gecikme? Bir çekirdekte 2 milyar satırlık bir tabloyu taramak, 20 çekirdekte 20 tabloyu paralel olarak taramaktan 20 kat daha yavaştır. Veriler tek bir kaynakta çok yavaş işleniyor.

Neden yüksek kullanılabilirlik? Ya da her ikisini aynı anda ve aynı anda her parçanın birkaç kopyasını yapmak için verileri keseriz - çoğaltma, yüksek kullanılabilirlik sağlar.

1.3 Basit bir örnek "elle nasıl yapılır"

Koşullu parçalama, 32 belge için test.documents test tablosu kullanılarak ve bu tablodan her biri yaklaşık 2 belge olmak üzere 16 test tablosu oluşturularak kesilebilir test.docs00, 01, 02, ..., 15.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

Neden hakkında? Önsel olarak kimliğin nasıl dağıtıldığını bilmediğimiz için, eğer 1'den 32'ye kadarsa, o zaman her biri tam olarak 2 belge olacaktır, aksi takdirde olmaz.

Neden burada yapıyoruz. 16 masa yaptıktan sonra ihtiyacımız olandan 16 tanesini "alabiliriz". Neye çarparsak çarpalım, bu kaynakları paralel hale getirebiliriz. Örneğin yeterli disk alanı yoksa bu tabloları ayrı disklere ayrıştırmak mantıklı olacaktır.

Bütün bunlar maalesef ücretsiz değil. Kanonik SQL standardı söz konusu olduğunda (SQL standardını uzun süredir yeniden okumadım, belki de uzun süredir güncellenmedi), herhangi bir SQL sunucusuna söylemek için resmi bir standart sözdizimi olmadığından şüpheleniyorum. : "Sevgili SQL sunucusu, beni 32 parça yapın ve bunları 4 diske bölün. Ancak bireysel uygulamalarda, temelde aynı şeyi yapmak için genellikle belirli bir sözdizimi vardır. PostgreSQL'in bölümleme mekanizmaları var, MySQL'in MariaDB'si var, Oracle muhtemelen tüm bunları uzun zaman önce yaptı.

Yine de, veritabanı desteği olmadan ve standart çerçevesinde elle yaparsak, o zaman veri erişiminin karmaşıklığı ile koşullu olarak ödeme yaparız . Basit bir SELECT * FROM belgelerinin olduğu yerde WHERE id=123, şimdi 16 x SELECT * FROM docsXX. Ve rekoru anahtarla almaya çalışsak iyi olur. Erken bir kayıt aralığı elde etmeye çalışıyor olsaydık çok daha ilginç olurdu. Şimdi (vurguluyorum, aptalsak ve standart çerçevesinde kalırsak), bu 16 SELECT * FROM'un sonuçlarının uygulamada birleştirilmesi gerekecek.

Hangi performans değişikliğini bekleyebilirsiniz?

  • Sezgisel olarak - doğrusal.
  • Teorik olarak - alt doğrusal, çünkü Amdahl yasası.
  • Pratik olarak, belki neredeyse doğrusal olarak, belki değil.

Aslında, doğru cevap bilinmiyor. Parçalama tekniğinin akıllıca uygulanmasıyla, uygulamanızın performansında önemli bir süper lineer bozulma elde edebilirsiniz ve DBA bile kızgın bir pokerle koşarak gelir.

Bunun nasıl başarılabileceğini görelim. Ayarı PostgreSQL shards=16 olarak ayarlamanın ve sonra kendi kendine kalkmasının ilginç olmadığı açıktır. Parçalamadan 32'ye 16 kat yavaşladığımızdan nasıl emin olabileceğimizi düşünelim - bu, bunun nasıl yapılmaması açısından ilginç.

Hızlandırma veya yavaşlatma girişimlerimiz her zaman klasiklerle karşılaşacaktır - herhangi bir talebin mükemmel bir paralelliği olmadığını, her zaman bazı tutarlı kısımlar olduğunu söyleyen eski güzel Amdahl yasası.

1.4 Amdahl yasası

Her zaman serileştirilmiş bir bölüm vardır.

Sorgu yürütmenin her zaman paralelleştirilmiş bir kısmı vardır ve her zaman paralelleştirilmemiş bir kısmı vardır. Size tamamen paralel bir sorgu gibi görünse bile, en azından her parçadan alınan satırlardan istemciye göndereceğiniz sonuç satırının koleksiyonu her zaman oradadır ve her zaman sıralıdır.

Her zaman tutarlı bir kısım vardır. Küçük olabilir, genel arka planda tamamen görünmez olabilir, devasa olabilir ve buna bağlı olarak paralelleştirmeyi güçlü bir şekilde etkiler, ancak her zaman vardır.

Ek olarak, etkisi değişiyor ve önemli ölçüde büyüyebilir, örneğin, tablomuzu 64 kayıttan 4 kayıttan oluşan 16 tabloya indirirsek - hadi riskleri yükseltelim - bu kısım değişecektir. Tabii bu kadar devasa veriye bakılırsa bir cep telefonu ve 2 MHz 86 işlemci üzerinde çalışıyoruz ve aynı anda açık tutulabilecek kadar dosyamız yok. Görünüşe göre, bu tür girdilerle her seferinde bir dosya açıyoruz.

  • Toplam = Seri + Paralel idi . Örneğin, DB içindeki tüm iş paraleldir ve seri, sonucu müşteriye gönderir.
  • Total2 = Seri + Paralel/N + Xserial Oldu . Örneğin, genel ORDER BY, Xserial>0 olduğunda.

Bu basit örnekle, bazı Xserial'lerin göründüğünü göstermeye çalışıyorum. Her zaman serileştirilmiş bir kısım olması ve verilerle paralel olarak çalışmaya çalıştığımız gerçeğine ek olarak, bu veri dilimlemeyi sağlamak için ek bir kısım vardır. Kabaca konuşursak, ihtiyacımız olabilir:

  • bu 16 tabloyu veritabanının dahili sözlüğünde bulun;
  • dosyaları aç;
  • bellek ayırmak;
  • bellek ayırma;
  • sonuçları birleştir;
  • çekirdekler arasında senkronize edin.

Bazı senkronizasyon dışı efektler hala görünüyor. Önemsiz olabilirler ve toplam zamanın milyarda birini kaplayabilirler, ancak her zaman sıfır değildirler ve her zaman oradadırlar. Onların yardımıyla, parçalamadan sonra performansı önemli ölçüde kaybedebiliriz.

Bu, Amdahl yasası hakkında standart bir resimdir. Burada önemli olan, ideal olarak düz olması ve doğrusal olarak büyümesi gereken doğruların bir asimptota dönüşmesidir. Ancak internetten gelen grafik okunamadığı için bence sayılarla daha görsel tablolar yaptım.

Diyelim ki istek işlemenin yalnızca %5'ini alan serileştirilmiş bir kısmı var: serial = 0.05 = 1/20 .

Sezgisel olarak, istek işlemenin yalnızca 1/20'sini alan serileştirilmiş bir parça ile, istek işlemeyi 20 çekirdek için paralelleştirirsek, yaklaşık 20, en kötü durumda 18 kat daha hızlı olacak gibi görünüyor.

Aslında matematik kalpsiz bir şeydir :

duvar = 0,05 + 0,95/çekirdek sayısı, hızlanma = 1 / (0,05 + 0,95/çekirdek sayısı)

%5'lik bir serileştirilmiş kısım ile dikkatlice hesaplarsanız, teorik ideale kıyasla %51 olan hızlanmanın 10 kat (10.3) olacağı ortaya çıkıyor.

8 çekirdek = 5.9 = %74
10 çekirdek = 6.9 = %69
20 çekirdek = 10.3 = %51
40 çekirdek = 13.6 = %34
128 çekirdek = 17.4 = %14

Birinin üzerinde çalıştığı görev için 20 çekirdek (isterseniz 20 disk) kullandıktan sonra, teorik olarak asla 20 kattan fazla hızlanma elde edemeyiz, ancak pratikte - çok daha az. Ayrıca paralel sayısı arttıkça verimsizlik de büyük oranda artmaktadır.

Serileştirilmiş işin yalnızca %1'i kaldığında ve %99'u paralelleştirildiğinde, hızlanma değerleri bir miktar iyileşir:

8 çekirdek = 7.5 = %93
16 çekirdek = 13.9 = %87
32 çekirdek = 24.4 = %76
64 çekirdek = 39.3 = %61

Doğal olarak tamamlanması saatler süren mükemmel bir termonükleer sorgu için ve hazırlık çalışması ve sonucun birleştirilmesi çok az zaman alır (seri = 0.001), zaten iyi bir verimlilik göreceğiz:

8 çekirdek = 7.94 = %99
16 çekirdek = 15.76 = %99
32 çekirdek = 31.04 = %97
64 çekirdek = 60.20 = %94

Lütfen hiçbir zaman %100'ü göremeyeceğimizi unutmayın . Özellikle iyi durumlarda, örneğin %99,999'u görebilirsiniz, ancak tam olarak %100'ü göremezsiniz.