Çoğu API hız sınırı uygulaması, saf proxy döndürme ile kolayca aşılır — ancak aynı döndürme, dakikalar içinde kötüye kullanım karşıtı sezgisel yöntemleri tetikler. Asıl zorluk, yalnızca sınırın altında kalmak değil, bunu bir bot gibi görünmeden yapmaktır. Bu, iki farklı hız sınırı kapsamını (IP başına ve anahtar başına) anlamayı, jitter eklenmiş geri çekilme uygulamayı, havuz döndürmeyi rastgeleleştirmeyi ve istek zamanlamasını organik trafiği taklit edecek şekilde şekillendirmeyi gerektirir. Bir proxy havuzu üzerine katmanlanmış token bucket deseni, sağlam bir temel sağlar.
IP Başına ve Anahtar Başına: Hız Sınırlamasının İki Ekseni
Hız sınırları en az iki bağımsız boyutta çalışır: kaynak IP ve API anahtarı (veya token). Tek bir anahtar saatte 5.000 isteğe izin verebilir (GitHub’ın kimliği doğrulanmış sınırı), ancak aynı anahtar tek bir IP’den daha düşük bir patlama tavanında sınırlanabilir. Kimliği doğrulanmamış istekler daha da kısıtlıdır — genellikle IP başına saatte 60 istek. IP boyutunu göz ardı etmek, bir 429 Too Many Requests (RFC 6585) yanıtını tetiklemenin en hızlı yoludur. Bir proxy havuzu, tek bir kaynağı doyurmamak için istekleri birden çok IP’ye dağıtmalıdır, ancak her IP yine de aynı anahtarı paylaşır. Anahtarın genel sınırı saatte 5.000 ise ve 50 proxy’niz varsa, anahtar düzeyindeki sayaç devreye girmeden önce her proxy saatte yalnızca 100 istek yapabilir. Tek bir satır kod yazmadan önce her iki sınırı da haritalayın.
Jitter ile Geri Çekilme: Kibar ve Tahmin Edilebilir Arasındaki Fark
Jitter olmadan üstel geri çekilme bir parmak izidir. Sunucular, mükemmel şekilde ikiye katlanan aralıklarla gelen istekleri görür ve bunları otomatik olarak işaretler. Çözüm tam jitter’dır: sleep(random.uniform(0, min(cap, base * 2 ** attempt))). Bu, yeniden denemeleri zaman penceresine yayarak deseni gerçek kullanıcıların patlamasından ayırt edilemez hale getirir. AWS’nin üstel geri çekilme ile ilgili kendi belgeleri, tam da bu nedenle jitter önerir. Aşağıdaki Python parçacığı, sabit bir hızda yeniden dolduran, boşken jitter ile uyuyan ve her başarılı edinimde proxy’yi döndüren bir token bucket uygular:
import time
import random
from collections import deque
class TokenBucketProxyPool:
def __init__(self, proxies, rate, burst):
self.proxies = deque(proxies)
self.rate = rate # tokens per second
self.burst = burst
self.tokens = burst
self.last_refill = time.monotonic()
def refill(self):
now = time.monotonic()
elapsed = now - self.last_refill
self.tokens = min(self.burst, self.tokens + elapsed * self.rate)
self.last_refill = now
def acquire(self):
while True:
self.refill()
if self.tokens >= 1:
self.tokens -= 1
self.proxies.rotate(1) # simple rotation, but see section below
return self.proxies[0]
else:
sleep_time = (1 - self.tokens) / self.rate
jitter = random.uniform(0, sleep_time * 0.5)
time.sleep(sleep_time + jitter)
# Usage: pool = TokenBucketProxyPool(proxies, rate=2.0, burst=10)
# proxy = pool.acquire() # blocks until token available
Proxy Havuzu Döndürme: Rastgele Seç, Round-Robin Yapma
Bir proxy listesinde sıralı round-robin tespit edilebilir. 1.2.3.4, ardından 5.6.7.8, ardından 9.10.11.12 adreslerinden kilit adımında istek gören bir sunucu, bu deseni IP’ler arasında ilişkilendirir. Bunun yerine, proxy’leri değiştirmeli olarak rastgele seçin ve proxy başına bir soğuma süresi ekleyin. Genel proxy dizinleri %60–80 başarısızlık oranı bildirir — 429 veya bağlantı hatası döndüren bir proxy, en az 60 saniye boyunca ölü kuyruğa alınmalıdır. Yakın zamanda başarılı olan proxy’lerin seçilme olasılığının daha yüksek olduğu ağırlıklı rastgele seçim uygulayın. Yukarıdaki token bucket, netlik için basit bir rotate(1) kullanır; üretimde bunu random.choice() ile değiştirin ve proxy başına başarısızlık sayılarını izleyin.
İstek Şekillendirme: Ortalamayı Taklit Et, Çizgiyi Aşma
Mükemmel bir token bucket ve proxy havuzuyla bile, saniyede tam olarak 2,0 olan sabit bir istek hızı doğal değildir. Gerçek kullanıcılar duraklar, toplu işlem yapar ve istekler arası aralıkları değiştirir. Her acquire() çağrısından önce küçük bir rastgele gecikme (örneğin, time.sleep(random.uniform(0.1, 0.5))) ekleyin ve token bucket’ın hızını her birkaç dakikada bir ±%10 değiştirin. Ancak, API’nin belgelenmiş hız sınırı penceresini aşan gecikmeler eklemeyin — bu amacı bozar. Amaç, meşru istemcilerden oluşan bir küme gibi görünürken sınırın içinde kalmaktır. Aşırı şekillendirme (örneğin, insan benzeri yazma gecikmeleri eklemek) boşa çabadır; API, tuş vuruşları arasındaki zamanlamayla değil, istek sıklığıyla ilgilenir.
Etik Azaltma: Çizginin Nerede Olduğunu Bil
Burada açıklanan her teknik, API’nin Hizmet Şartları’nı ihlal edene kadar meşru bir optimizasyondur. Çoğu ToS, “hız sınırlarını aşmayı” veya “hizmete erişmek için otomatik araçlar kullanmayı” açıkça yasaklar. ToS’yi okumak isteğe bağlı değildir. API anahtar başına dakikada 100 isteğe izin veriyorsa, her biri dakikada 2 istek yapan 50 proxy kullanmak uyumludur. Her biri dakikada 100 istek yapan 100 proxy kullanmak uyumlu değildir — jitter’ınız ne kadar akıllıca olursa olsun, bu kötüye kullanımdır. Ayrım niyet ve hacimdir. Bir proxy havuzu üzerine katmanlanmış token bucket bir araçtır; etik olarak genel bir dizini kazıyan aynı araç, küçük bir API’ye DDoS saldırısı yapmak için de kullanılabilir. Hız sınırı hedeflerinizi belgeleyin, 429’lar için günlüklerinizi denetleyin ve belgelenmiş anahtar başına tavanı asla aşmayın. Daha fazla iş hacmine ihtiyacınız varsa, daha yüksek bir sınır isteyin veya özel bir plan için ödeme yapın.