Daha Fazla Yükü Taşımak İçin İki Yol
Hoş Geldiniz
Bir hizmet yük altında zorlanmaya başladığında, bir operatör bir seçimle karşı karşıya kalır. Mevcut makineyi büyütmek (daha fazla CPU, daha fazla RAM, daha hızlı diskler). Ya da aynı işi yapan daha fazla makine eklemek.
İlk yol dikey ölçeklendirme (scale up) olarak geçer. İkinci yol yatay ölçeklendirme (scale out) olarak geçer.
Bu ders, neden neredeyse tüm modern web mimarileri yatay ölçeklendirmeyi seçtiğini ve iş yükünün bu seçimi mümkün kılan hangi özelliğe sahip olduğunu öğretir. Cevap tek bir kelimenin içinde gizlidir: durum.
Sonunda şunları anlayacaksınız:
- Dikey ve yatay ölçeklendirmenin maliyet eğrileri & her birinin ne zaman mantıklı olduğu
- 'Durumlu' (stateful) ve 'durumsuz' (stateless) terimlerinin pratikte ne anlama geldiği & bunlardan birinin neden ucuz bir şekilde çoğaltılabildiği
- Beklenen ve ani yük altında bir replika filoyu boyutlandıran matematik
- Bir katmanın kuyruk diziliminin (queueing) kritik noktasının ötesinde çökmesini engelleyen pay (headroom) kuralı
- Durumun nerede barındırılması gerektiği (asla kaybolmaz) & ölçeklenmesi gereken katmanlardan nasıl dışarıya itileceği
Neden Yatay Ölçeklendirme Bir Eşiğin Ötesinde Kazanır
Dikey Ölçeklendirme: Daha Büyük Tek Bir Kutu
Avantajlar: basit. Kod değişikliği yok. Koordinasyon yok. Aynı süreç artık daha fazla CPU'ya sahip.
Dezavantajlar: tavan. Ticari olarak satın alınabilen en büyük sanal makinenin sonlu bir RAM ve çekirdek sayısı vardır. Bu seviyenin üzerinde, daha fazla kapasite için ne kadar para harcarsanız harcayın, ek alan satın alınamaz. Maliyetler, bir sağlayıcının sunduğu ideal noktanın ötesinde süperlineer olarak artar. Bu tek makinede yaşanan bir arıza, tüm hizmeti devre dışı bırakır.
Yatay Ölçeklendirme: Birçok Daha Küçük Makine
Avantajlar: tavan yok (makine satın almak ve koordine etmek için ödeme yapma isteğinize kadar). Kapasite, kopya sayısıyla öngörülebilir bir şekilde doğrusal olarak artar. Tek bir kopyanın arızalanması, kapasitenin %100'ünü değil, 1/N'ini kaldırır.
Dezavantajlar: iş yükünün bunu desteklemesi gerekir. Bazı iş yükleri (tek büyük bir veritabanı, canlı oturumları tutan durumlu bir oyun sunucusu) yatay ölçeklendirmeye direnç gösterir. Koordinasyon ve yük dağıtımı operasyonel endişeler haline gelir.
Kesişim noktası: tek bir makine arızasına dayanması gereken herhangi bir üretim hizmeti, en az iki makinede çalışmalıdır. İki makineyi kabul ettiğiniz anda, zaten yatay ölçeklendirmeyi seçmiş olursunuz. Bundan sonra soru 'yapmalı mıyız?' değil, 'bir sonraki kopyayı ne kadar ucuza ekleyebiliriz?'dir.
Temel kolaylaştırıcı: makinenin kendisinde istek başına durum (state) tutmayan bir iş yükü. Bu durumda herhangi bir kopya herhangi bir isteğe yanıt verebilir ve bir kopya eklemek, koordinasyona gerek kalmadan kapasite ekler.
Pratikte Durumlu (Stateful) ve Durumsuz (Stateless)
Durum Asla Kaybolmaz, Sadece Taşınır
Durumlu bileşen: Kaybı davranışı değiştirecek bilgiyi tutar. Kullanıcı hesaplarını tutan bir veritabanı. Oturum belirteçlerini tutan bir önbellek. Uzun süreli bir akış bağlantısını belirli bir kullanıcıya sabitleyen bir işçi.
Durumsuz bileşen: Kaybı önemli olacak hiçbir bilgi tutmaz. Bir isteği okuyan, veritabanına sorgu gönderen ve bir yanıt yazan bir web katmanı. Her istek kendi başınadır; katman istekler arasında hiçbir şey hatırlamaz.
Temel içgörü: durum bir sistemden asla kaybolmaz. Onu tutmak için tasarlanmış bir katmana taşınır (bir veritabanı, bir Redis kümesi, bir nesne deposu). Bu sayede trafiğe maruz kalan katmanlar durumsuz hale gelebilir ve durumsuz katmanlar yatay olarak ölçeklenir, çünkü herhangi bir kopya herhangi bir isteğe yanıt verebilir.
Pratik test: Bu katmandaki bir süreci rastgele öldürüp yeniden başlatırsanız, herhangi bir kullanıcı yanlış bir yanıt alır veya oturumu kaybolur mu? Evet ise, durum tutmaktadır. Hayır ise, tutmamaktadır.
Örnekler
- İstekleri okuyan, Postgres'e sorgu gönderen ve JSON döndüren bir Python web süreci: durumsuz. Durum Postgres'te yaşar.
- Kullanıcı alışveriş sepetlerini yerel bellekte tutan bir Python web süreci: durumlu. Süreç öldürülürse sepetler kaybolur.
- Sohbet kullanıcılarına açık bağlantılar tutan bir WebSocket sunucusu: bağlantı anlamında durumlu (stateful). Süreç kapatıldığında bağlantılar düşer; istemcilerin yeniden bağlanması gerekir. Genellikle bu tür sistemler, dikkatli yapılandırma (yapışkan oturumlar, tutarlı hash'leme) ile yatay ölçeklenmeye hâlâ uygundur.
- Postgres'in önündeki bir Redis önbelleği: önbellek içeriği için durumlu (stateful), ancak önbellek kaçırılmaları (cache miss) kabul edilebilir ise bu sorun değildir. Bir replika arızası veri kaybına değil, önbellek kaçırılmasına yol açar.
Yatay ölçeklenmeye yönelik tasarım = durumun (state), ölçeklenmesi gereken katmandan dışarı itilmesidir.
Şüpheli Katmanı Denetleyin
Bir ekip, bir ters yönlendirmeli proxy (reverse proxy) arkasında 6 arka uç sanal makinede (VM) bir öneri API'si çalıştırıyor. Uygulama: istekten bir kullanıcı ID'si okur, kullanıcının son aktivitelerini Postgres'ten alır, bir puanlama algoritması çalıştırır ve önerilen öğelerin listesini döndürür. İki standart dışı davranış:
- Uygulama, süreç belleğinde (process memory) bir 'son kullanıcı aktivitesi' önbelleği tutar; bu önbellek kullanıcının ilk isteğinde doldurulur ve sonraki isteklerde yeniden kullanılır.
- Uygulama yapışkan oturumları (sticky sessions) kullanır: bir kullanıcı VM #3'e ulaştığında, sonraki tüm istekleri VM #3'e gider (proxy, bir çereze (cookie) dayalı yapışkan yönlendirme için yapılandırılmıştır).
Kopya Formülü
En Basit Kapasite Formülü
Bir katman durumdan bağımsız (stateless) hale geldiğinde, boyutlandırması aritmetik bir işlem haline gelir. Sabit durum yükünün aynı hızda gelip gitmesi için yeterli sayıda replikaya ihtiyacınız var; ayrıca ani artışlar için pay bırakmalısınız.
Formül:
replicas = ⌈ (peak_load × surge_factor) / per_replica_capacity ⌉ + headroom
Burada:
- peak_load: Normal işlemede beklenen maksimum sürekli istek/saniye
- surge_factor: Zirvenin üzerindeki kısa süreli ani artışları kapsayan bir çarpan (öngörülebilir trafik için genellikle 1.5x ile 2x arası, viral / öngörülemez trafik için 3x veya daha fazla)
- per_replica_capacity: Kabul edilebilir gecikme ve kullanım oranında bir replikanın işlediği istek/saniye (genellikle doyumda değil, %70 CPU'da ölçülür)
- headroom: Birkaç replika arızası durumunda katmanın çökmesini önlemek için eklenen replikalar (küçük filolarda genellikle 1-2 replika, daha büyük olanlarda %10-20)
Çözümlü örnek: Bir arka uç, her replika başına %70 CPU ile 100 istek/sn işliyor. Zirve yükü 600 istek/sn. Ara sıra 2 katlık ani artışlar bekleniyor. 2 replika arızasına dayanabilmeniz isteniyor.
replikalar = ⌈ (600 × 2) / 100 ⌉ + 2 = 12 + 2 = 14 replika
%80 Kuralı
Replika başına kapasite doğrudan doygunluk noktası değildir. Kapasiteyi asla %100'de değil, %70-80 CPU'da ölçün.
Yaklaşık %80 kullanım oranının ötesine geçildiğinde, kuyruk eğrileri keskin bir şekilde yükselir: %60 kullanım oranında 10 ms'de işlenen bir kuyruk, %90 kullanım oranında 80 ms'de işlenir. Önce kırılan şey, verimlilik değil gecikmedir. (Bu eğri matematiksel olarak geometry_of_stateless_horizontal_scaling eşlikçi dersinde türetilecektir.)
Otomatik Ölçeklendirme (Autoscaling) ve Statik Tahsis
Statik: Zirve × ani artış payı için tahsis yapın ve tepe dışı saatlerde düşük kullanım oranıyla çalışmanın maliyetini kabul edin.
Otomatik Ölçeklendirme: Bir denetleyici, gözlemlenen kullanım oranına, hedef gecikmeye veya kuyruk derinliğine dayanarak replikaları ekler ve kaldırır.
Otomatik ölçeklendirme uyarısı: Soğuk başlatma süresi önemlidir. Yeni bir replika 2 dakika içinde açılıyorsa, otomatik ölçeklendirme 30 saniyelik bir ani artışa yanıt veremez. Olgun otomatik ölçeklendirme, ölçeklendirme eşiğinin hemen altında, önceden ayrılmış ılık replika havuzunu korur.
Yeni Bir Servis İçin Filoyu Boyutlandırın
Ekip, bir video meta verisi API'si başlatmayı planlıyor. Testler, tek bir replikanın %70 CPU ve 50 ms p99 gecikme ile 250 istek/sn işlediğini gösteriyor. Pazarlama, prime-time saatlerinde zirve yükün 4.000 istek/sn olacağını öngörüyor. Planlanan bir tanıtım etkinliği, yükü kısa süreliğine 3 katına çıkarabilir. Servisin, hayatta kalanlarda %80 kullanım oranını aşmadan 3 eşzamanlı replika arızasını atlatabilmesini istiyorsunuz.
Soğuk Başlatma, Yavaş Tahliye ve Diğer Gerçek Kenar Durumları
Gerçek Filolar Gerçek Kenar Durumlarına Sahiptir
Formül, kopyaların (replica) anında belirdiğini, trafiği anında kabul ettiğini ve trafiği anında bıraktığını varsayar. Üretim ortamında bunların hiçbiri geçerli değildir.
Soğuk başlatma (Cold start): Yeni bir kopyanın (replica) işletim sistemini başlatması, süreci (process) çalıştırması, yapılandırmayı yüklemesi, önbellekleri (cache) ısıtması ve sağlık kontrollerinden geçmesi gerekir. Bu süre 5 saniye (konteyner yeniden başlatma) ile 5 dakika (tam VM açılışı + görüntü çekimi) arasında değişebilir. Otomatik ölçeklendirme, bu gecikmeden daha kısa süreli ani artışlara (burst) tepki veremez.
Yavaş tahliye (Slow drain): Havuzdan çıkarılan bir kopyanın (replica), sonlandırılmadan önce devam eden istekleri tamamlaması için zamana ihtiyacı vardır. Aksi takdirde kullanıcılar kesik kalan yanıtlar görür. Ters yönlendirmeler (reverse proxy) tahliyeyi destekler (yeni istekleri kabul etmeyi durdur, aktif olanları tamamla) ancak bu işlem saniyelerden dakikalara kadar sürebilir.
Sıcak havuz: Üretim filoları, sinyalle trafiği almaya hazır, önceden tahsis edilmiş ancak boşta duran replika havuzunu ayakta tutar. Hızlı ani artış tepkisi için küçük ve sürekli bir maliyet ödülünü tercih eder.
Bağlantı tahliyesi (draining) ile anında kesme (kill): Zarif kapanış (graceful shutdown) önemlidir. Tahliyeyi tetikleyen bir SIGTERM, SIGKILL'den daha uzun sürer ancak kullanıcı isteklerini bozmaz.
Sağlık denetimi penceresi: Az önce başlayan bir replika, veritabanı bağlantı havuzu ısınmadan önce ilk sağlık denetimini geçebilir; ardından proxy gerçek trafiği gönderir ve ilk on iki istek yavaş olur. Sağlık denetimlerini, yalnızca süreç canlılığını değil, gerçek yolu test edecek şekilde ayarlayın.
Yapışkanlık sızıntısı (Stickiness creep): Nominal olarak durum tutmayan (stateless) katmanlar zamanla yapışkanlık kazanır (CDN önbellekleri, DNS çözümleyici önbellekleri, bağlantı havuzları). Yine de farklı davranan "aynı replikalar"dan şüphelenin.
Sıcak Havuz mu, Reaktif Otomatik Ölçeklendirme mi?
Video meta verisi API'niz (önceki sorudaki aynı API, sürekli zirve + ani artış için 51 replika boyutlandırılmış), yeni viral bir video yüklendiğinde her seferinde 30 saniyelik, normal yükün 5 katına çıkan bir ani artışa maruz kalır. Otomatik ölçeklendirme, soğuk başlangıçtan yeni bir replika eklemek için şu anda 90 saniye sürüyor (görüntü çekme + ısınma). Bu 90 saniyelik boşlukta gecikme keskin şekilde artıyor ve bazı istekler zaman aşımına uğruyor.
Kısıtlar Altında Durumsuz (Stateless) Bir Katman Tasarlayın
Sentez
Neden yatay ölçeklendirmenin küçük bir eşiğin ötesinde kazandığını, pratikte durumun (state) ne anlama geldiğini, beklenen ve ani yük altında bir filoyu nasıl boyutlandıracağınızı ve yatay ölçeklendirmenin nerede sınırlara takıldığını öğrendiniz.
Dördünü de uygula.
feed.example.com adlı bir sosyal akış API'si için bir arka uç katmanı tasarla. Kısıtlamalar: replika başına kapasite %70 CPU'da 200 istek/sn; beklenen tepe yük 1500 istek/sn; ani artış faktörü 2.5x (dönemsel olarak trend olan hikayeler); 2 eşzamanlı replika arızasına dayanıklılık; soğuk başlatma süresi 60 saniye; ani artışlar 45 saniye sürebilir; bütçe bazı boşta kapasiteye izin veriyor ancak 2.5x kalıcı tahsisata izin vermiyor.
Bu Kursun Sıradaki Adımı
Bu Dersin Sonraki Adımı
Artık durumdan bağımsız (stateless) bir katman için işleyen bir zihinsel modele sahipsiniz: neden ölçeklendiği, nasıl boyutlandırıldığı, kenarlarında neyin bozulduğu ve büyümeye ihtiyaç duyan katmanın dışına itildiğinde durumun nereye taşınması gerektiği.
Bu dersteki sonraki ders (cs_distsys_ingress_egress_separation), daha ince bir sorunu ele alır: mükemmel boyutlandırılmış bir durumdan bağımsız katman bile, gelen ve giden trafik aynı ağ yolunu paylaştığında şaşırtıcı şekillerde başarısız olabilir. Klasik örnek, kendisine bağlanmaya çalışan bir vekil (proxy) içerir; çözüm ise tek bir katmanı farklı sorumluluklara sahip iki katmana ayırmayı gerektirir.
Eşlikçi ders: geometry_of_stateless_horizontal_scaling, kuyruklama eğrisini, bir replika filosu için Little Yasası'nın uygulanmasını ve %80 kullanım oranı dizininin geometrik anlamını türetir.
İyi iş. Yola devam.