Bir uygulama milyonlarca kullanıcıya hizmet veriyorsa, saniyede milyonlarca sorgu işliyorsa, altyapının binlerce sunucuyla çalışması kaçınılmazdır. Ancak bu ölçekte en kritik bileşen her zaman veritabanıdır. Tek bir veritabanı sunucusu bu yükü kaldıramaz; bu yüzden verileri ve sorguları birden çok sunucuya dağıtmak gerekir. İşte burada devreye 'database sharding' yani veritabanı parçalama giriyor. Peki, 768 sunucuyu tek bir veritabanı gibi göstermek mümkün mü? İşte bu yazıda, küçük bir düğümden petabaytlarca veri depolayan devasa bir shard kümesine nasıl geçildiğini adım adım inceleyeceğiz.
Sharding'in neden gerekli olduğunu anlamak için önce daha az ölçeklenebilir yaklaşımların darboğazlarını kavramalıyız. Basit bir uygulama mimarisinde, istemci cihazı bir uygulama sunucusuna bağlanır; bu sunucu kimlik doğrulama, sayfa yüklemeleri ve tüm sunucu tarafı mantığını yönetir. Tüm kalıcı veriler (kullanıcı hesapları, gönderiler, ayarlar, mesajlar) veritabanı sunucusunda saklanır ve oradan alınır. Genellikle Postgres veya MySQL kullanılır. Büyük veritabanı sunucularında bile (onlarca CPU çekirdeği, yüzlerce GB RAM) darboğazlar hızla ortaya çıkar: yüksek sorgu hacmi nedeniyle CPU kısıtlamaları veya yoğun okuma/yazma trafiği nedeniyle G/Ç kısıtlamaları (IOPS).
Bu durum, Evrensel Ölçeklenebilirlik Yasası (USL) ile güzelce özetlenir: Kaynak çekişmesi, ölçeklenebilirliğin artan kaynaklarla doğrusal olmayan bir şekilde büyümesine neden olur ve belirli bir noktada tutarsızlık performansı düşürür. Postgres için de aynı durum geçerlidir. Kısa vadede bir çözüm, okuma replikaları kullanmaktır. Bu yapılandırmada, birincil sunucu korunur ve replikalar eklenir. Birincil, veri değişikliklerini replikalara sürekli bir akışla iletir. Yazma işlemleri (INSERT, UPDATE, DELETE) yalnızca birincile gidebilir; aksi takdirde çakışan veriler ortaya çıkar. Ancak okuma sorguları replikalara yönlendirilebilir. Çoğu uygulamada okuma oranı yazmadan çok daha yüksek olduğu için bu, önemli ölçüde daha fazla ölçeklenebilirlik sağlar. Replikalar ayrıca yüksek kullanılabilirlik ve veri dayanıklılığı için de gereklidir.
Sonuç ve Değerlendirme
Sunucuları dikey olarak ölçeklendirmek (CPU/RAM artırmak) ve replika eklemek ancak bir yere kadar işe yarar. Yüksek yazma hacmi durumunda, hiçbir okuma replikası sorunu çözmez. Postgres, taahhüt edilmiş bir yazmayı onaylamadan önce değişikliği yazma-ahead log (WAL) kaydına yazmalı ve bu logu kalıcı depolamaya flush etmelidir. WAL, birincildeki tüm bağlantılar arasında paylaşılan bir kaynaktır. Bu, tüm veritabanı genelinde tek bir yazma darboğazı anlamına gelir. Ayrıca, replika birincilin tüm verilerinin tam bir kopyasıdır; verileri dağıtmaz. Yedekleme de büyük bir sorundur: Monolitik bir veritabanının yedeklenmesi, bant genişliği sınırlamaları nedeniyle saatler hatta günler sürebilir.
Sharding, bu üç darboğazı verileri ve sorguları birden çok birincil sunucuya dağıtarak çözer. Veri açısından, tek bir düğümün depolayabileceği ve yazma verimliliği sınırlı olduğu için faydalıdır. Sorgular açısından ise ağ ara bağlantıları ve CPU'lar aynı anda yalnızca belirli sayıda sorguyu işleyebilir. Birkaç terabayt verinin ötesinde sharding her ölçekte faydalıdır. Örneğin, 2 TB veri için dört shard kullanılabilir; her biri 500 GB depolar ve toplam sorgu trafiğinin 1/4'ünü işler. Bir petabayt veri (1 milyon GB) depolamak gerektiğinde ise çok daha fazla shard gerekir. Bu durumda, her biri ~4 TB depolayan, birincil + 2 replika içeren 256 shard kullanılabilir. Bu da 256 * 3 = 768 sunucu demektir!
Sharding ile dağıtık bir veritabanı yönetmek, uygulama arka ucuna önemli bir karmaşıklık ekler. Sistemin hangi verinin hangi sunucuya gideceğine, hangi sorgunun hangi sunucuya yönlendirileceğine, birden çok shard'ı aynı anda sorgulayan sorguların nasıl işleneceğine, yedeklemelerin nasıl alınacağına, sistem genelinde sağlık izlemesine ve başarısız bir sunucuya nasıl yanıt verileceğine karar vermesi gerekir. Tüm bu sorunların üstesinden gelmek için iyi bir sistem şarttır. Ancak bu makalenin odaklandığı asıl soru şu: Bu 768 sunucu, uygulamalarımıza nasıl tek bir tutarlı veritabanı gibi görünebilir? Cevap, sharding katmanıdır. Uygulama sunucuları, karmaşık bir sisteme bağlanmak yerine tek bir bağlantı noktası üzerinden shard yöneticisine bağlanır. Shard yöneticisi, sorguyu analiz eder, hangi shard(lar)ın ilgili olduğunu belirler ve sorguyu uygun sunuculara iletir. Sonuçları birleştirip uygulamaya döndürür. Bu sayede uygulama, arka planda 768 sunucu olduğunu bilmeden, sanki tek bir veritabanına sorgu gönderiyormuş gibi çalışır. Shard yöneticisi ayrıca yük dengeleme, hata toleransı ve yedekleme gibi işlemleri de üstlenir.
Sharding, büyük ölçekli veritabanı yönetiminin olmazsa olmazıdır. 768 sunucuyu tek bir mantıksal veritabanına dönüştürmek, doğru araçlar ve stratejilerle mümkündür. Citus, Vitess gibi açık kaynak çözümler veya AWS Aurora, Google Cloud Spanner gibi bulut tabanlı hizmetler bu işi kolaylaştırır. Önemli olan, sharding anahtarını doğru seçmek, veri dağılımını dengeli tutmak ve sorguların çoğunun tek bir shard'da çözülebilmesini sağlamaktır. Aksi takdirde, çapraz shard sorguları performansı olumsuz etkileyebilir. Ayrıca, shard'lar arasında veri tutarlılığı ve dağıtık işlemler (distributed transactions) dikkatle yönetilmelidir.
Uzmanların Görüşleri
Sonuç olarak, Postgres sharding, petabayt ölçeğinde veri depolamak ve milyonlarca sorguyu işlemek için en kanıtlanmış yöntemdir. 768 sunucuyu tek bir veritabanı gibi göstermek, doğru shard yöneticisi ve dikkatli bir tasarımla mümkündür. Bu yaklaşım, yazma darboğazını ortadan kaldırır, yedekleme sürelerini kısaltır ve yatay ölçeklenebilirlik sağlar. Eğer siz de büyük ölçekli bir veritabanı yönetiyorsanız, sharding stratejilerini değerlendirmek, uzun vadede başarının anahtarı olacaktır.
Kaynak: planetscale.com