Software Architecture

Dayanıklı Mimari İnşa Etmek: Başarısızlıklara Dayanan Sistemler Tasarlamak

Bulut-native hesaplama ve dağıtık mikro servisler çağında, kesinti süresi artık sadece bir rahatsızlık değil, iş açısından kritik bir risktir. Kullanıcılar 7/24 erişilebilirlik bekler ve tek bir başarısızlık noktası sistem genelinde bir kesintiyi tetikleyebilir. Dayanıklı mimari yalnızca hatalardan kaçınmakla ilgili değildir; bu, başarısızlığın kaçınılmaz olduğunu varsayan ve sistemi buna göre yapılandıran bir tasarım felsefesidir.

Orta ve ileri düzey geliştiriciler için dayanıklılığı anlamak temel hata yönetiminin ötesine geçer. Sistemin kullanıcı deneyimini bozmadan başarısızlıkları algılamasını, izole etmesini ve toparlanmasını sağlayan belirli desenlerin uygulanmasını gerektirir. Bu yazıda, dağıtık sistemlerde zincirleme başarısızlıkları önlemek için hayati önem taşıyan Devre Kesici (Circuit Breaker) desenine odaklanarak dayanıklı mimarinin temel bileşenlerini keşfedeceğiz.

Başarısızlık Felsefesi

Dayanıklılık, bileşenlerin başarısız olacağı varsayımına dayanır. Ağ bölünmeleri, servis zaman aşımı ve kaynak tükenmesi yaygın durumlar olarak karşımıza çıkar. Dayanıklı bir sistem tüm başarısızlıkları önlemeye çalışmaz—ki bu imkansızdır—ancak bunların etkisini en aza indirir. Temel ilkeler şunları içerir:

  • Hızlı Başarısızlık (Fail Fast): Kaynakları çaresiz operasyonlarda harcamamak için hataları erken tespit edin.
  • Yumuşak Bozulma (Graceful Degradation): Temel işlevselliği, gereksiz servisler kapalı olsa bile sunmaya devam edin.
  • İzole Etme: Bir servisteki bir başarısızlığın başka bir serviste kaynak tükenmesine (örneğin, iş parçacığı havuzu tükenmesi) neden olmasını önleyin.

Devre Kesici Deseninin Uygulanması

Dayanıklılığı elde etmek için kullanılan en etkili araçlardan biri Devre Kesici desenidir. Bu desen, bir uygulamanın büyük olasılıkla başarısız olacak bir işlemi tekrar tekrar denemesini engeller. Bir elektrik sigortası gibi düşünün: Bir arıza tespit edildiğinde devre kesilir ve arıza çözülene kadar akış durur.

Yazılımda devre kesicinin üç durumu vardır:

  1. Kapalı (Closed): İstekler normal şekilde akar. Başarısızlık oranı bir eşiği aşarsa, devre kesici tetiklenir.
  2. Açık (Open): İstekler hemen reddedilir veya bir yedek (fallback) ile işlenir. Sistemin toparlanmasına zaman tanınır.
  3. Yarı Açık (Half-Open): Bir zaman aşımından sonra sistem, servisin toparlanıp toparlanmadığını görmek için sınırlı sayıda test isteğine izin verir.

Aşağıda, dekoratörler kullanarak temel bir Devre Kesici uygulamasını gösteren basitleştirilmiş bir Python örneği bulunmaktadır:

import time
from functools import wraps

class CircuitBreakerOpen(Exception):
    pass

def circuit_breaker(fail_threshold=5, recovery_timeout=60):
    def decorator(func):
        times_opened = 0
        opened_at = 0

        @wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal times_opened, opened_at
            
            # Devrenin açık olup olmadığını ve kurtarma süresinin geçip geçmediğini kontrol et
            if times_opened >= fail_threshold:
                if time.time() - opened_at < recovery_timeout:
                    raise CircuitBreakerOpen(f"Devre {func.__name__} için açık")
                else:
                    # Yarı açık duruma sıfırla (basitleştirilmiş)
                    times_opened = 0
            
            try:
                return func(*args, **kwargs)
            except Exception as e:
                times_opened += 1
                if times_opened >= fail_threshold:
                    opened_at = time.time()
                raise e
        return wrapper
    return decorator

# Kullanım Örneği
@circuit_breaker(fail_threshold=3, recovery_timeout=10)
def call_external_service():
    # Bir hatayı simüle et
    raise ConnectionError("Servis kullanılamıyor")

Sonuç

Dayanıklılık, geliştirme sürecinin sonunda eklenen bir özellik değildir; mimarinizin dokusuna ilk günden itibaren işlenmesi gereken bir kalite özelliğidir. Devre Kesici gibi desenleri benimseyerek, üstel geri çekilme (exponential backoff) ile sağlam yeniden deneme mekanizmaları uygulayarak ve yumuşak bozulma için tasarlayarak, olumsuz koşullar altında bile kararlılığını koruyan sistemler inşa edebilirsiniz. Bir sonraki mikro servisinizi veya dağıtık uygulamanızı yeniden yapılandırırken kendinize şu soruyu sorun: "Bu bağımlılık başarısız olursa ne olur?" Bu sorunun cevabı, dayanıklılığın temelini oluşturur.

Share: