Replication & Partitioning Konseptleri
Bir uygulamamız olduğunu düşünelim. Bu uygulamanın yaptığı iş kapasitesi sebebiyle uygulamayı ölçekledik ve önüne de bir load balancer koyduk. Ancak, artık uygulama daha fazla yükü handle edeceği için, ilgili database’e giden istek sayısı da artacaktır. Database de tek makinada duruyor ise kapasitesine ulaşması ve performans kayıpları yaşaması hızlanacaktır. Bu noktada artık replication ve partitioning konseptlerine yönelmek gerekiyor.
1. Replication
Replica bir data stroge’in kopyasını oluşturup read yükünü dağıtmak demektir. Replicalar oluşturarak bir database’in read kapasitesini artırabiliriz. Replication konseptinin en yaygın yolu da leader-follower topolojisidir. Client write (insert, update, delete) isteklerini leader’a yollar. Leader bu istekleri write-ahead log’una yazar. Daha sonra followerlar ya da replikalar leader’a bağlanarak log entrylerini ondan stream eder ve local olarak commit eder. Log entryler sıra numarasına sahip olduğu için, followerlar herhangi bir anda disconnect olup tekrar reconnect olabilir.
LEADER FOLLOWER YAPISI İLE İLGİLİ DETAYLI BİLGİYE BU YAZIMDAN ULAŞABİLİRSİNİZ.
Replication database avalibility’sini de artırmayı sağlar. Load balancer otomatik olarak hatalı replicayı tespit ederek ona giden istekleri kesip diğer replicalara yollayabilir. İlgili node tekrar healthy duruma geldiğinde de request gönderimi tekrar başlayabilir. Aynı şekilde leader node fail olduğunda, güncel bir replika leaderin yerine geçebilir.
Bunun yanında, replication spesifik workloadları isolate etmek için de kullanılabilir. Örneğin, maliyetli raporlama queryleri gibi queryler, diğer iş yükünü bloke etmemesi açısından farklı bir replicaya gönderilebilir. Aynı şekilde, indexingin maliyetinin yüksek olduğu durumlarda, bir replika üzerinde index atılıp replikayı leader ile switch edebiliriz.
1.1. Senkron ve Asenkron Replication
Leader node ve followerlar arası replikasyon tamamen senkron, tamamen asenkron ya da ikisinin kombinasyonu şeklinde olabilir.
Eğer replikasyon tamamen asenkron işliyor ise leader bir write isteğini aldığında, bu isteği broadcast şeklinde followerlara yönlendirir ve followerlardan ack yanıt beklemeden client’a response yollar. Bu yaklaşım response time’i minimize eder ancak yeterince fault tolerant bir yapı değildir. Örneğin leader clienta acknowledgei dönüp ancak followerlara ilgili write’ı broadcast edemeden crash olursa, data kaybı olacaktır. Ya da followerların yarısından bir fazlasına bu istek bir şekilde yazılamazsa yine rollback olacakıtr.
Replikasyon süreci tamamen senkron işliyorsa, leader process tüm followerlardan ack mesajını alana kadar client’a sonuç dönmeyerek bekler. Bu da, followerlardan birinin yavaşlığının dahi overall süreyi etkilemesine neden olur. Ayrıca tek bir replica dahi unavaliable olsa data store unavailable olur (cap teoremini hatırlayım). Bu da ölçeklenebilir bir yaklaşım değildir. Ne kadar çok followerınız olursa, bu riskler o kadar artar.
Pratikte relational databaseler hem senkron hem de asenkron replikasyonun kombinasyonunu destekler. Örneğin, postgresqlde bir follower asenkron replika olsa bile senkrona configure edilebilir. Ya da 1 adet sync replica backup’ı tutup bunu leader çöktüğünde %100 up-to-date replika olarak düşünüp yerine swicth edip data lossu sıfırlayabilirsiniz.
Konsept olarak iyi bir failover mekanızması, leaderin fail oluduğu anlayıp sync followeri yeni leader olarak yükseltip followerları onu takip edecek noktaya otomatik set edip, clientten gelen requestleri de yeni lidere yönlendirebilmeli.
Replication konusundaki önemli bir nokta ise replicationın yalnızca readleri scale edebiliyor oluşudur. Writeları scale etme gibi bir katkısı yoktur. Bir diğer nokta ise replication tek başına yapıldığı takdirde tüm datanın tek bir makinaya fit olabileceği kabuluyle ilerler. Bu kısıtlar da bizi partitioning konseptine yöneltir.
2. Partitioning
Partitioning datayı parçalara ayırıp dağıtma işlemidir. Partitioning bize databasede hem read’i hem de write’ı ölçekleme imkanı sunar. Genel olarak traditional databaseler bu özelliği desteklemese de destekleyen dbler de mevcuttur. Partitioning sisteme ekstra complexity katar. Partitioning yapıldığı dataların nodelara nasıl partition olacağının kararının verilmesi ve dengelenmesi gerekir. Ayrıca, client tarafından gelen querylerin partitionlara uygun bir şekilde yönlenip sonucun partitionlardan toplanabilmesi gerekir. Bu gibi bir durumda group by ya da join gibi sorguların nasıl kompleksleşeceğini siz düşünün. Atomik transactionlar için de 2PC implementasyonu gerekebilir.
Aslında relational databaselerdeki temel problem databaselerin tek bir makinaya fit olabileceği yaklaşımıyla tasarlanmış olmasıdır. Bu yüzden relational databaseler ACID transactionları ya da joinler gibi ölçeklenmesi zor konuları içerir. Relational databaseler, disk alanının maliyetli olduğu ve disk üzerindeki yükü azaltmak için verileri normalize etmenin bir öncelik olduğu ve sorgu zamanında verileri birleştirmelerle normalleştirmenin önemli bir maliyeti olsa bile bir öncelik olduğu bir çağda tasarlandı. Ancak zaman değişti ve storage’ın ucuz CPU’nun ise pahalı olduğu bir döneme girdik.
Yaygın olarak kullanılan iki tür partitioning yöntemi vardır. Biri range partitioning diğeri de hash partitioning. Buradaki önemli yeter koşul ise keylerin fazla olması gerekliliğidir. Örneğin, partition keyinizi çeşitliliği az olan hatta bir boolean değer üzerinden verirseniz en fazla 2 partitiona olanak sağlarsınız.
2.1 Range Partition
Range partitionda datalar sözlüksel olarak sıraya dizilerek partition yapılır. Range scanleri hızlı yapabilmek adına her partition diskte sorted olarak store edilir.Burada ilk kritik nokta partition boundyleridir. Range dağılımı eşide yakın yapınca anlamlı hale gelir. Diğer türlü bir dengesizlik olacaktır.
Diğer bir konu da hotspotdır. Örneğin, data tarihlere göre partition yapıldığında ve requestler hep ilgili bir tarih aralığına geliyorsa, örneğin o güne ait datalara, yine requestler bir node’da toplanacaktır.
Static ve Dynamic Partitioning
Requestlerin ya da datanın boyutu arttıkça da node sayısını arttırmak gerekecek aynı şekilde data küçülür ya da requestler azalırsa costu düşürmek adına node sayısı azaltılabilmelidir. Bu olaya rebalancing denir. Rebalancing yapılırken sistemin çalışmayı kesmemesi gerekir. Bunun için farklı yollar vardır. Bir çözüm normalden fazla partition yaratıp her node’a birden fazla partition assign etmektir. Buna static partitioning denir. Çünkü zaman içinde partition sayısı değişmez. Sisteme yeni bir node eklendiğinde bazı partitionlar var olan nodetan yeni node’a kayar ki sistem balance kalabilsin. Bu durumun sıkıntısı ise partition sayısının sabit olması ve kolayca değiştirilememesidir. Doğru sayıya karar vermek zordur. Fazlası performans kaybına yol açar, azı ise scalibilityi düşürür. Diğer bir yaklaşım ise talebe yönelik partition yaratan dynamic partitioning. Sistem tek partitionla başlar. Partition dolduğunda ikiye bölerek yeni partition yaratır. Bu sayede her bir partition yarı yarıya dengelidir. aynı şekilde partitionlardan komşu olanlar küçülürse ve cold olursa tekrar birleşir.
2.2 Hash Partitioning
Ana mantık deterministik bir stringi belirli bir rangede random bir number(hash)’a mapleyen bir hash function kullanmaya dayanır. Bu da keyin hashlerinin range boyunca düzenli yayılmasını garanti eder.
Daha sonra, hashin her bir alt kümesini bir partitiona atarız. Bunu yapmanın bir yolu hashin modunu almaktır. Bu her ne kadar her partitionın 3 aşağı 5 yukarı eşit sayıda entrye sahip olmasını sağlasa da, access pattern düzgün değilse, hotspot ihtimalini engellemez. Bu durumda, toplam partition sayısını artırarak partitionın daha da bölünmesi gerekir. Alternatif olarak, örneğin başına rastgele bir önek getirilerek keylerin sub keylere bölünmesi gerekir.
Çoğu key farklı bir partitiona kaydırılacağı için ve assignmentları değişeceği için yeni partition eklendiğinde hashleri partitionlara modül operatörüyle ayırmak problemli bir yaklaşım olabilir . Suffling data işlemi oldukça maliyetli bir işlemdir çünkü network bandwidth ve diğer resourceları kullanır. İdeal olarak yeni bir partition eklendiğinde, sadece K/N key suffle edilir. Burada K key sayısı N ise partition sayısıdır. Bu özelliğe sahip yaygın olarak kullanılan partition stratejilerinden biri consistent hashingtir.
Consistent hashing ile bir hash fonkisyonu rastgele olarak hem partition identifiersları hem de keyleri circle’ın üzerine mapler ve her key saat yönünde circledaki en yakın gözüken partitiona maplenir.
Yeni partition eklendiğinde, yalnızca artık daire üzerinde onunla eşlenen keylerin yeniden atanması gerekir,.
Hash partitioning range partitioning’e kıyasla dezavantajı, partitionlar üzerindeki sort orderın kaybolmasıdır ki bu sort order da sıralı datalarda efektif scanı sağlamaktadır. Ancak Partitionın içerisindeki individual datalar hala secondary key üzerinde sortlanabilir.
İlgili yazılar