Python'da asyncio kütüphanesi tarafından yönlendirilen eşzamansız programlama, yüksek performanslı ve G/Ç yoğun uygulamalar geliştirme şeklini kökten değiştirdi. Ancak büyük eşzamanlılık, büyük sorumluluk getirir. Yüzlerce koreutin aynı anda istek gönderdiğinde, aşağı akış hizmetlerini aşırı yüklemenin, API hız sınırlarına takılmanın veya zincirleme arızalar nedeniyle kendi uygulamanızın çökmesinin riski katlanarak artar. Bu kılavuzda, Python'un eşzamansız ekosistemi kullanarak iki kritik dayanıklılık desenini—Hız Sınırlama ve Devre Kesiciler—nasıl uygulayacağımızı keşfedeceğiz.
Eşzamansız Eşzamanlılığın Zorluğu
Eşzamanlı kodda, tek bir yavaş istek iş parçacığını bloklar. Eşzamansız bir bağlamda ise binlerce eşzamanlı görev başlatabilirsiniz. Bu görevler, dakikada 60 istek gibi bir sınırı uygulayan harici bir API ile etkileşime girdiğinde, uygulamanız hemen HTTP 429 hataları alır; bu da kaynak israfına ve hizmet sağlayıcısıyla potansiyel itibar kaybına yol açar. Ayrıca, aşağı akışta bir hizmet çöktüğünde, gecikme olmadan tekrar denemek veya meşgul bekleme yapmak sunucunuzun kaynaklarını tüketebilir ve kendi kullanıcılarınız için Hizmet Reddi (DoS) durumuna neden olabilir.
Bu nedenle dayanıklılık sadece bir özellik değil; üretim kalitesindeki eşzamansız uygulamalar için temel bir gerekliliktir. Bu zorlukları, mümkün olduğunda ağır bağımlılıklardan kaçınarak sıfırdan yeniden kullanılabilir bir RateLimiter (Hız Sınırlayıcı) ve bir CircuitBreaker (Devre Kesici) oluşturarak ele alacağız.
Eşzamansız Hız Sınırlayıcı Uygulama
Bir hız sınırlayıcı, işlev çağrılarının hızını kontrol eder. Eşzamansız uygulamalar için, sınır ulaşıldığında koreutlerin meşgul döngüye girmek yerine verimli bir şekilde beklemesini sağlayan bir mekanizmaya ihtiyacımız vardır. Token Bucket (Token Havuzu) algoritması popüler bir seçenektir, ancak Python'da basitlik ve verimlilik açısından, sabit pencere veya token tabanlı sınırlama için bayrak (semaphore) tabanlı bir yaklaşım iyi çalışır.
Aşağıda, eşzamanlılık sınırlarını uygulamak için bir bayrak ve zaman tabanlı sınırları uygulamak için bir uyku mekanizması kullanan eşzamansız bir hız sınırlayıcının sağlam bir uygulaması yer almaktadır.
import asyncio
import time
class AsyncRateLimiter:
def __init__(self, rate: float, per: float):
"""
:param rate: İzin verilen çağrı sayısı.
:param per: Saniye cinsinden zaman periyodu.
"""
self.rate = rate
self.per = per
self.semaphore = asyncio.Semaphore(rate)
self.last_call_time = 0.0
self.lock = asyncio.Lock()
async def acquire(self):
# Öncelikle eşzamanlı istek sınırlarına saygı duymak için bayrağı bekleyin
await self.semaphore.acquire()
async with self.lock:
elapsed = time.time() - self.last_call_time
if elapsed < self.per:
wait_time = self.per - elapsed
await asyncio.sleep(wait_time)
self.last_call_time = time.time()
def __aenter__(self):
return self
def __aexit__(self, exc_type, exc_val, exc_tb):
self.semaphore.release()
return False
# Kullanım Örneği
async def fetch_data(session, url, limiter):
async with limiter:
# Bir API isteğini simüle edin
print(f"{url} alınıyor")
# await session.get(url)
await asyncio.sleep(0.5)
return "Veri"
async def main():
limiter = AsyncRateLimiter(rate=2, per=1.0) # Saniyede 2 istek
tasks = [fetch_data(None, "https://api.example.com", limiter) for _ in range(10)]
await asyncio.gather(*tasks)
# asyncio.run(main())
Bu örnekte, semaphore (bayrak), periyot içinde eşzamanlı olarak en fazla rate görevin yürütülmesini sağlar. Kilitleme ve zaman damgası kontrolü, genel hızın saygı duyulmasını garanti eder. Bu, uygulamanızın üçüncü taraf API'leri tarafından yasaklanmasını önler.
Devre Kesici Deseni
Hız sınırlama aşağı akış hizmetlerini korurken, Devre Kesici deseni uygulamanızı aşağı akış arızalarından korur. Bir hizmet sürekli olarak başarısız oluyorsa, devre kesici "açılır", çağrı yapmadan hızlıca başarısız olur ve hizmetin toparlanması için zaman tanır.
Üç durumu olan basit bir devre kesici uygulayacağız: Kapalı (normal çalışma), Açık (hızlı başarısızlık) ve Yarı Açık (toparlanmayı test etme).
import asyncio
from enum import Enum
import time
class CircuitState(Enum):
CLOSED = "CLOSED"
OPEN = "OPEN"
HALF_OPEN = "HALF_OPEN"
class CircuitBreaker:
def __init__(self, failure_threshold=5, recovery_timeout=60):
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.failure_count = 0
self.state = CircuitState.CLOSED
self.last_failure_time = 0
async def call(self, func, *args, **kwargs):
if self.state == CircuitState.OPEN:
if time.time() - self.last_failure_time > self.recovery_timeout:
self.state = CircuitState.HALF_OPEN
print("Devre kesici yarı açık, toparlanma test ediliyor...")
else:
raise Exception("Devre kesici AÇIK")
try:
result = await func(*args, **kwargs)
self._on_success()
return result
except Exception as e:
self._on_failure()
raise
def _on_success(self):
self.failure_count = 0
self.state = CircuitState.CLOSED
def _on_failure(self):
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = CircuitState.OPEN
print("Arızalar nedeniyle devre kesici açıldı.")
Bu deseni entegre ederek uygulamanız kendini iyileştirme yeteneği kazanır. Aşağı akış hizmeti toparlandığında, HALF_OPEN (Yarı Açık) durumu tek bir test isteğinin geçmesine izin verir. Başarılı olursa devre kapanır; başarısız olursa yeniden açılır ve mücadele eden hizmet üzerinde daha fazla baskı oluşmasını önler.
Üretim Dayanıklılığı İçin Desenleri Birleştirme
Üretim ortamında bu desenler genellikle birlikte çalışır. Yaygın bir mimari desen, HTTP istemcinizi hem bir hız sınırlayıcı hem de bir devre kesici ile sarmalayıp kullanmaktır. Bu, API sağlayıcısının kısıtlamalarına saygı duyarken aynı zamanda kendi uygulama mantığınızı tamamen çökmeye karşı da korur.
Bunları birleştirirken, her zaman hız sınırlayıcıyı önce uygulayın. Bu, devre kesiciden geçmeye çalışan istek sayısını en aza indirerek sistem üzerindeki yükü azaltır. Devre kesici ardından kalıcı arızalara karşı son bir koruma katmanı olarak hareket eder. Bu katmanlı savunma stratejisi, Python'da mikroservisler ve yüksek verimli veri boru hatları oluşturmak için esastır.
Sonuç
Python asyncio'yu ustalıkla kullanmak sadece sözdizimini anlamaktan daha fazlasını gerektirir; sistem dayanıklılığına derin bir takdir duymayı gerektirir. Özel hız sınırlayıcılar ve devre kesiciler uygulayarak, uygulamalarınızın yalnızca hızlı değil, aynı zamanda sağlam, güvenilir ve bağımlı oldukları altyapıya saygılı olduğundan emin olursunuz. Bu desenler isteğe bağlı lüksler değil; ciddi her türlü üretim kalitesindeki Python uygulaması için zorunluluklardır. Gerçek dünyanın baskılarına dayanıklı yazılımlar oluşturmak için bu uygulamaları bir sonraki eşzamansız projenize entegre etmeye başlayın.