Bloga geri dön

Proxy Üzerinden Yük Dengeleme: 10000+ RPS'ye Kadar Parselleme ve API İsteklerini Ölçeklendirme

Pazar yerlerini taramak, API ile çalışmak ve otomasyon için proxy havuzları aracılığıyla yük dağıtımına dair kapsamlı bir rehber: mimari, dengeleme algoritmaları ve yapılandırma için pratik örnekler.

📅7 Şubat 2026
```html

Pazar yerlerinde binlerce sayfa taradığınızda, toplu API istekleri gönderdiğinizde veya yüzlerce hesapla otomasyon yaptığınızda, proxy üzerinden doğru yük dağılımı kritik hale gelir. Akıllı bir dengeleme olmadan, engellemeler, zaman aşımı ve performans düşüşleri ile karşılaşabilirsiniz. Bu kılavuzda, yük dağıtım mimarisini, dengeleme algoritmalarını ve yüksek yük sistemleri için pratik stratejileri inceleyeceğiz.

Bu materyal, veri tarama, API isteklerinin otomasyonu ile çalışan veya iş hedefleri için büyük proxy havuzlarını yöneten geliştiriciler ve teknik uzmanlar için hazırlanmıştır.

Proxy üzerinden yük dengelemesi neden gereklidir

Proxy üzerinden yük dengelemesi, yüksek yük sistemlerinin birkaç kritik sorununu çözer. İlk ve en önemlisi — engellemelere karşı koruma. Bir kaynağa (pazar yeri, sosyal medya API'si, arama motoru) binlerce istek gönderdiğinizde, hedef sunucu tek bir IP adresinden anormal yüksek bir aktivite görür ve onu engeller. İsteklerinizi onlarca veya yüzlerce proxy arasında dağıtmak, aktivitenizi normal kullanıcıların davranışına benzetir.

İkinci sorun — performanstır. Bir proxy sunucusunun sınırlı bir bant genişliği vardır (genellikle 100-1000 Mbit/s) ve sınırlı sayıda eşzamanlı bağlantı işleyebilir. Dakikada 10.000 sayfa taradığınızda veya toplu API istekleri gönderdiğinizde, tek bir proxy sistemin darboğazı haline gelir. Dengeleme, yeni proxy ekleyerek bant genişliğini yatay olarak ölçeklendirmeyi sağlar.

Üçüncü görev — güvenilirliktir. Eğer bir proxy arızalanırsa (teknik arıza, engelleme, kiralama süresinin sona ermesi), sistem otomatik olarak trafiği çalışan proxy'lere yönlendirir. Dengeleme ve sağlık kontrolleri mekanizması olmadan, bir proxy'nin arızalanması tüm sistemi durdurabilir.

Gerçek bir örnek: Rakip fiyatlarını izlemek için Wildberries'i tararken, her saat 50.000 ürünü işlemeniz gerekir. Bu, saniyede yaklaşık 14 istektir. Tek bir proxy bu yükü kaldırabilir, ancak Wildberries, bir adresten 100-200 isteği sonra IP'yi engeller. İstekleri 20 ikamet eden proxy arasında dağıtarak, her IP üzerindeki yükü saniyede 0.7 isteğe düşürürsünüz — bu, normal bir kullanıcının aktivitesi gibi görünür.

Dördüncü neden — coğrafi dağılımdır. Birçok hizmet, kullanıcının bölgesine bağlı olarak farklı içerikler veya fiyatlar gösterir. Farklı ülkelerden ve şehirlerden proxy'ler arasında dengeleme yapmak, tüm hedef bölgelerden veri toplamayı sağlar. Örneğin, Ozon'daki fiyatları izlemek için Moskova, Saint Petersburg, Yekaterinburg ve diğer büyük şehirlerden proxy'lere ihtiyacınız vardır.

Yük dağıtım sistemi mimarisi

Proxy üzerinden yük dengeleme sisteminin klasik mimarisi birkaç bileşenden oluşur. En üst seviyede bir dengeleyici (load balancer) bulunur — gelen görevleri (tarama istekleri, API çağrıları) alıp mevcut proxy'ler arasında dağıtan bir yazılım modülüdür. Dengeleyici, ayrı bir hizmet olarak çalışabilir veya uygulamaya entegre edilebilir.

İkinci bileşen — proxy havuzu yöneticisidir (proxy pool manager). Tüm mevcut proxy'lerin IP adresi, portu, protokolü (HTTP/SOCKS5), coğrafi konumu, türü (ikamet eden, mobil, veri merkezi), mevcut durumu (aktif, engellenmiş, kontrol ediliyor) gibi özelliklerini saklar. Havuz yöneticisi, yeni proxy'lerin eklenmesi, çalışmayanların kaldırılması ve erişilebilirliğin periyodik kontrolünden sorumludur.

Üçüncü bileşen — izleme ve sağlık kontrolü sistemidir. Her proxy'nin çalışabilirliğini sürekli kontrol eder: test istekleri gönderir, yanıt süresini ölçer, bağlantının başarısını kontrol eder. Eğer proxy yanıt vermez veya hatalar dönerse, sistem onu erişilemez olarak işaretler ve geçici olarak döngüden çıkarır.

Bileşen Fonksiyon Teknolojiler
Load Balancer Proxy'ler arasında isteklerin dağıtılması HAProxy, Nginx, Python/Node.js kütüphaneleri
Proxy Pool Manager Proxy listesinin yönetimi Redis, PostgreSQL, bellek içi depolama
Health Check System Proxy'nin erişilebilirliğini kontrol etme Zamanlanmış görevler, Celery, cron
Rate Limiter İstek sıklığının kontrolü Token bucket, leaky bucket algoritmaları
Monitoring & Metrics Performans metriklerinin toplanması Prometheus, Grafana, ELK Stack

Dördüncü bileşen — rate limiter (istek sıklığı sınırlayıcıdır). Her proxy'nin hedef kaynağa izin verilen istek sıklığını aşmadığından emin olur. Örneğin, Instagram'ı tarıyorsanız ve platformun IP'yi dakikada 60 isteği sonra engellediğini biliyorsanız, rate limiter bir proxy üzerinden dakikada 50 isteği aşmasına izin vermez ve güvenlik payı bırakır.

Beşinci bileşen — metrik ve analiz sistemidir. Her proxy'nin performans verilerini toplar: başarılı istek sayısı, hata sayısı, ortalama yanıt süresi, engelleme oranı. Bu veriler, dengeleme algoritmalarının optimizasyonu ve problemli proxy'lerin tespit edilmesi için kullanılır.

Dengeleme algoritmaları: Round Robin, En Az Bağlantı, Ağırlıklı

Round Robin algoritması — en basit ve yaygın dengeleme yöntemidir. Proxy'leri listeden sırayla döngüye alır: ilk istek proxy №1 üzerinden, ikinci istek proxy №2 üzerinden, üçüncü istek proxy №3 üzerinden ve bu şekilde devam eder. Liste bittiğinde, dengeleyici başa döner. Bu algoritma, tüm proxy'ler aynı performansa sahipse yükü eşit bir şekilde dağıtır.

class RoundRobinBalancer:
    def __init__(self, proxies):
        self.proxies = proxies
        self.current_index = 0
    
    def get_next_proxy(self):
        proxy = self.proxies[self.current_index]
        self.current_index = (self.current_index + 1) % len(self.proxies)
        return proxy

# Kullanım
proxies = [
    "http://proxy1.example.com:8080",
    "http://proxy2.example.com:8080",
    "http://proxy3.example.com:8080"
]

balancer = RoundRobinBalancer(proxies)
for i in range(10):
    proxy = balancer.get_next_proxy()
    print(f"İstek {i+1} → {proxy}")

Least Connections (en az bağlantı) algoritması, mevcut en az aktif bağlantıya sahip proxy'yi seçer. Bu, isteklerin farklı işleme sürelerine sahip olduğu durumlarda faydalıdır. Örneğin, bir tarama isteği 100 ms sürebilirken, diğeri 5 saniye sürebilir (sayfa yavaş yüklenirse). Least Connections, yeni istekleri daha az yüklenmiş proxy'lere otomatik olarak yönlendirir.

class LeastConnectionsBalancer:
    def __init__(self, proxies):
        self.proxies = {proxy: 0 for proxy in proxies}
    
    def get_next_proxy(self):
        # En az bağlantıya sahip proxy'yi seç
        proxy = min(self.proxies.items(), key=lambda x: x[1])[0]
        self.proxies[proxy] += 1
        return proxy
    
    def release_proxy(self, proxy):
        # İstek tamamlandığında sayacı azalt
        self.proxies[proxy] -= 1

# Kullanım için bağlam yöneticisi ile
balancer = LeastConnectionsBalancer(proxies)

def make_request(url):
    proxy = balancer.get_next_proxy()
    try:
        # Seçilen proxy üzerinden istek yap
        response = requests.get(url, proxies={"http": proxy})
        return response
    finally:
        balancer.release_proxy(proxy)

Weighted Round Robin (ağırlıklı döngü) klasik Round Robin'i genişleterek, her proxy'ye performansına veya kalitesine bağlı olarak bir ağırlık atar. Daha yüksek ağırlığa sahip proxy'ler daha fazla istek alır. Bu, farklı kalitede proxy'leriniz olduğunda faydalıdır: örneğin, yüksek hızda premium ikamet eden proxy'ler ve sınırlamaları olan ucuz veri merkezi proxy'leri.

class WeightedRoundRobinBalancer:
    def __init__(self, weighted_proxies):
        # weighted_proxies = [(proxy, weight), ...]
        self.proxies = []
        for proxy, weight in weighted_proxies:
            # Proxy'yi ağırlık kadar listeye ekle
            self.proxies.extend([proxy] * weight)
        self.current_index = 0
    
    def get_next_proxy(self):
        proxy = self.proxies[self.current_index]
        self.current_index = (self.current_index + 1) % len(self.proxies)
        return proxy

# Ağırlıklarla kullanım
weighted_proxies = [
    ("http://premium-proxy1.com:8080", 5),  # yüksek kalite
    ("http://premium-proxy2.com:8080", 5),
    ("http://cheap-proxy1.com:8080", 2),    # düşük kalite
    ("http://cheap-proxy2.com:8080", 1)     # çok düşük kalite
]

balancer = WeightedRoundRobinBalancer(weighted_proxies)

Random (rastgele seçim) algoritması, mevcut proxy'lerden rastgele birini seçer. Uygulaması Round Robin'den daha basittir ve çok sayıda proxy (100+) olduğunda iyi çalışır. Rastgele dağılım, yeterli istek hacminde otomatik olarak dengelenir. Dezavantajı — kısa süreli dengesiz yüklenmelere yol açabilir.

IP Hash — hedef URL veya başka bir parametreye dayalı olarak proxy'yi seçen bir algoritmadır. Bu, aynı kaynağa yapılan isteklerin her zaman aynı proxy üzerinden gitmesini garanti eder. Oturumlar kullanan veya bir IP'den ardışık istekler gerektiren siteler için faydalıdır (örneğin, kimlik doğrulama + veri alma).

Proxy havuzları yönetimi: döngü ve sağlık kontrolleri

Etkili bir proxy havuzunun yönetimi, her proxy'nin durumunu sürekli izlemeyi ve otomatik döngü yapmayı gerektirir. Sağlık kontrolü — proxy'nin erişilebilirliğini test etmek için periyodik bir kontrol işlemidir. Genellikle güvenilir bir hizmete (örneğin, httpbin.org veya kendi uç noktanıza) basit bir GET isteği gönderilir ve IP adresi hakkında bilgi döner.

import requests
import time
from datetime import datetime

class ProxyHealthChecker:
    def __init__(self, test_url="http://httpbin.org/ip", timeout=10):
        self.test_url = test_url
        self.timeout = timeout
    
    def check_proxy(self, proxy_url):
        """Proxy'nin çalışabilirliğini kontrol eder"""
        try:
            start_time = time.time()
            response = requests.get(
                self.test_url,
                proxies={"http": proxy_url, "https": proxy_url},
                timeout=self.timeout
            )
            response_time = time.time() - start_time
            
            if response.status_code == 200:
                return {
                    "status": "healthy",
                    "response_time": response_time,
                    "timestamp": datetime.now(),
                    "ip": response.json().get("origin")
                }
            else:
                return {
                    "status": "unhealthy",
                    "error": f"HTTP {response.status_code}",
                    "timestamp": datetime.now()
                }
        except requests.exceptions.Timeout:
            return {
                "status": "unhealthy",
                "error": "timeout",
                "timestamp": datetime.now()
            }
        except Exception as e:
            return {
                "status": "unhealthy",
                "error": str(e),
                "timestamp": datetime.now()
            }

# Kullanım
checker = ProxyHealthChecker()
proxies = ["http://proxy1.com:8080", "http://proxy2.com:8080"]

for proxy in proxies:
    result = checker.check_proxy(proxy)
    print(f"{proxy}: {result['status']} ({result.get('response_time', 'N/A')}s)")

Havuz yönetim sistemi, çalışmayan proxy'leri otomatik olarak erişilemez olarak işaretlemeli ve periyodik olarak kontrolü tekrarlamalıdır. Yaygın bir strateji — circuit breaker pattern: ardışık üç başarısız kontrol sonrasında proxy, 5-10 dakika boyunca havuzdan çıkarılır, ardından tekrar kontrol edilir. Kontrol başarılı olursa, proxy aktif havuza geri döner.

class ProxyPoolManager:
    def __init__(self, health_checker, max_failures=3, cooldown_seconds=300):
        self.health_checker = health_checker
        self.max_failures = max_failures
        self.cooldown_seconds = cooldown_seconds
        
        self.proxies = {}  # {proxy_url: ProxyInfo}
    
    def add_proxy(self, proxy_url, metadata=None):
        """Proxy'yi havuza ekler"""
        self.proxies[proxy_url] = {
            "url": proxy_url,
            "status": "active",
            "failures": 0,
            "last_check": None,
            "cooldown_until": None,
            "metadata": metadata or {}
        }
    
    def get_active_proxies(self):
        """Aktif proxy listesini döndürür"""
        now = datetime.now()
        active = []
        
        for proxy_url, info in self.proxies.items():
            # Proxy'nin cooldown'da olup olmadığını kontrol et
            if info["cooldown_until"] and now < info["cooldown_until"]:
                continue
            
            if info["status"] == "active":
                active.append(proxy_url)
        
        return active
    
    def mark_failure(self, proxy_url):
        """Proxy kullanımında başarısızlığı işaretler"""
        if proxy_url not in self.proxies:
            return
        
        info = self.proxies[proxy_url]
        info["failures"] += 1
        
        if info["failures"] >= self.max_failures:
            # Cooldown'a al
            info["status"] = "cooldown"
            info["cooldown_until"] = datetime.now() + timedelta(seconds=self.cooldown_seconds)
            print(f"Proxy {proxy_url} cooldown'a alındı, {info['cooldown_until']} tarihine kadar")
    
    def mark_success(self, proxy_url):
        """Proxy kullanımında başarıyı işaretler"""
        if proxy_url not in self.proxies:
            return
        
        info = self.proxies[proxy_url]
        info["failures"] = 0
        info["status"] = "active"
        info["cooldown_until"] = None

Proxy döngüsü, belirli aralıklarla veya belirli bir istek sayısından sonra proxy'yi otomatik olarak değiştirme stratejisidir. Birkaç yaklaşım vardır: zamanla döngü (her 5-10 dakikada bir değişim), istek sayısına göre döngü (100-500 istektan sonra değişim), oturumlara göre döngü (bir tarama oturumu için bir proxy). Strateji seçimi, hedef sitenin gereksinimlerine bağlıdır.

Tavsiye: Pazar yerlerini (Wildberries, Ozon) taramak için en uygun strateji, istek sayısına göre döngüdür: her proxy için 50-100 istek, ardından değişim. Sosyal medya API'leri (Instagram, Facebook) ile çalışırken, oturumlara göre döngü kullanmak daha iyidir: bir proxy, tüm kimlik doğrulama → eylemler → çıkış döngüsü için kullanılmalıdır.

Rate limiting ve istek sıklığı kontrolü

Rate limiting — yük dengeleme sisteminin kritik bir bileşenidir. Hedef kaynağa izin verilen istek sıklığını aşmayı önler, bu da proxy'nin engellenmesine yol açabilir. İki ana algoritma vardır: Token Bucket (token kovası) ve Leaky Bucket (sızdıran kova).

Token Bucket şu şekilde çalışır: her proxy'nin sanal bir "kovası" vardır ve bu kova token'lerle doludur. Her token, bir istek için hak verir. Kova, belirli bir hızda (örneğin, saniyede 10 token) yavaşça dolmaya başlar. Kovanın maksimum kapasitesi sınırlıdır (örneğin, 50 token). Bir istek geldiğinde, sistem token'lerin varlığını kontrol eder: varsa bir token alır ve isteği gerçekleştirir, yoksa yeni bir token'ın gelmesini bekler.

import time
from threading import Lock

class TokenBucketRateLimiter:
    def __init__(self, rate, capacity):
        """
        rate: saniyedeki token sayısı
        capacity: kovadaki maksimum token sayısı
        """
        self.rate = rate
        self.capacity = capacity
        self.tokens = capacity
        self.last_update = time.time()
        self.lock = Lock()
    
    def _add_tokens(self):
        """Geçen zamana bağlı olarak token ekler"""
        now = time.time()
        elapsed = now - self.last_update
        new_tokens = elapsed * self.rate
        
        self.tokens = min(self.capacity, self.tokens + new_tokens)
        self.last_update = now
    
    def acquire(self, tokens=1):
        """Belirtilen sayıda token almaya çalışır"""
        with self.lock:
            self._add_tokens()
            
            if self.tokens >= tokens:
                self.tokens -= tokens
                return True
            return False
    
    def wait_and_acquire(self, tokens=1):
        """Token'ların gelmesini bekler ve alır"""
        while not self.acquire(tokens):
            # Bekleme süresini hesapla
            wait_time = (tokens - self.tokens) / self.rate
            time.sleep(wait_time)

# Her proxy için kullanım
proxy_limiters = {
    "http://proxy1.com:8080": TokenBucketRateLimiter(rate=10, capacity=50),
    "http://proxy2.com:8080": TokenBucketRateLimiter(rate=10, capacity=50)
}

def make_request_with_limit(url, proxy_url):
    limiter = proxy_limiters[proxy_url]
    limiter.wait_and_acquire()  # Token'ın kullanılabilir olmasını bekle
    
    response = requests.get(url, proxies={"http": proxy_url})
    return response

Leaky Bucket (sızdıran kova) farklı çalışır: istekler, belirli bir hızda "sızan" bir kuyrukta (kova) yer alır. Kova taşarsa, yeni istekler reddedilir veya beklemeye alınır. Bu algoritma, zaman içinde daha eşit bir yük dağılımı sağlar, ancak yoğunluk patlamalarında gecikmelere yol açabilir.

Farklı hedef platformlar için farklı limitler gereklidir. Instagram API'si, bir IP için saatte yaklaşık 200 isteğe izin verir (dakikada yaklaşık 3.3 istek). Wildberries, bir IP'den dakikada 100-200 isteği sonra engeller. Google Arama, dakikada 10-20 isteğe izin verir. Rate limiting sisteminiz, bu sınırlamaları dikkate almalı ve güvenlik payı eklemelidir (genellikle %20-30).

Platform İstek Limiti Önerilen Ayar
Instagram ~200 istek/saat Dakikada 2-3 istek (güvenlik payı ile)
Wildberries Dakikada 100-200 istek Dakikada 60-80 istek
Google Arama Dakikada 10-20 istek Dakikada 8-12 istek
Ozon Dakikada 50-100 istek Dakikada 30-50 istek
Facebook API 200 istek/saat Dakikada 2-3 istek

Performans izleme ve otomatik ölçeklendirme

Etkili bir yük dengeleme sistemi, ana metriklerin sürekli izlenmesini gerektirir. İlk metrik grubu — proxy'lerin performansı: ortalama yanıt süresi (response time), başarılı istek yüzdesi (success rate), zaman aşımı sayısı, 4xx ve 5xx hata sayısı. Bu veriler, problemli proxy'leri tespit etmek ve dengeleme algoritmalarını optimize etmek için kullanılır.

class ProxyMetrics:
    def __init__(self):
        self.metrics = {}  # {proxy_url: metrics_dict}
    
    def record_request(self, proxy_url, response_time, status_code, success):
        """İstek metriklerini kaydeder"""
        if proxy_url not in self.metrics:
            self.metrics[proxy_url] = {
                "total_requests": 0,
                "successful_requests": 0,
                "failed_requests": 0,
                "total_response_time": 0,
                "timeouts": 0,
                "errors_4xx": 0,
                "errors_5xx": 0
            }
        
        m = self.metrics[proxy_url]
        m["total_requests"] += 1
        
        if success:
            m["successful_requests"] += 1
            m["total_response_time"] += response_time
        else:
            m["failed_requests"] += 1
            
            if status_code == 0:  # zaman aşımı
                m["timeouts"] += 1
            elif 400 <= status_code < 500:
                m["errors_4xx"] += 1
            elif 500 <= status_code < 600:
                m["errors_5xx"] += 1
    
    def get_success_rate(self, proxy_url):
        """Başarılı istek yüzdesini döndürür"""
        m = self.metrics.get(proxy_url, {})
        total = m.get("total_requests", 0)
        if total == 0:
            return 0
        return (m.get("successful_requests", 0) / total) * 100
    
    def get_avg_response_time(self, proxy_url):
        """Ortalama yanıt süresini döndürür"""
        m = self.metrics.get(proxy_url, {})
        successful = m.get("successful_requests", 0)
        if successful == 0:
            return 0
        return m.get("total_response_time", 0) / successful
    
    def get_report(self, proxy_url):
        """Proxy'ye dair tam raporu döndürür"""
        m = self.metrics.get(proxy_url, {})
        return {
            "proxy": proxy_url,
            "total_requests": m.get("total_requests", 0),
            "success_rate": self.get_success_rate(proxy_url),
            "avg_response_time": self.get_avg_response_time(proxy_url),
            "timeouts": m.get("timeouts", 0),
            "errors_4xx": m.get("errors_4xx", 0),
            "errors_5xx": m.get("errors_5xx", 0)
        }

İkinci metrik grubu — sistemin genel performansı: toplam istek sayısı (RPS — requests per second), ortalama gecikme (latency), istek kuyruğunun boyutu, aktif proxy sayısı, proxy havuzunun kullanım yüzdesi. Bu metrikler, sistemin yükü kaldırıp kaldıramadığını veya ölçeklendirme gerekip gerekmediğini gösterir.

Otomatik ölçeklendirme (auto-scaling), yük durumuna bağlı olarak proxy'leri dinamik olarak eklemeyi veya kaldırmayı sağlar. Basit bir strateji: eğer havuzun ortalama yükü %80'in üzerine çıkarsa, sistem otomatik olarak yeni proxy'ler ekler. Eğer yük %30'un altına düşerse, sistem gereksiz proxy'leri kaldırır.

İzleme ayarına örnek: Wildberries'de saatte 100.000 ürünü taramak için (saniyede yaklaşık 28 istek) en az 30-40 proxy'ye ihtiyacınız var, her proxy için 60 istek limiti ile. Uyarıları ayarlayın: eğer başarı oranı %85'in altına düşerse veya ortalama yanıt süresi 3 saniyeyi aşarsa, sistem otomatik olarak havuzdan 10-15 yedek proxy eklemelidir.

Metrikleri görselleştirmek için Grafana'yı Prometheus veya ELK Stack ile kullanın. Zaman içinde RPS, yanıt süresi dağılımı, en hızlı/en yavaş 10 proxy, hata türlerine göre hata haritası gibi grafiklerle panolar oluşturun. Bu, sorunları hızlı bir şekilde tespit etmeyi ve sistemi optimize etmeyi sağlar.

Python ve Node.js ile pratik uygulama

Popüler kütüphaneleri kullanarak Python'da bir yük dengeleme sisteminin tam uygulamasını inceleyelim. Bu örnek, tüm tanımlanan bileşenleri bir araya getirir: dengeleyici, havuz yöneticisi, sağlık kontrolleri, rate limiting ve izleme.

import requests
import time
import random
from datetime import datetime, timedelta
from threading import Lock, Thread
from collections import defaultdict

class ProxyLoadBalancer:
    def __init__(self, proxies, algorithm="round_robin", rate_limit=10):
        """
        proxies: [{"url": "...", "weight": 1}, ...] şeklinde proxy listesi
        algorithm: round_robin, least_connections, weighted, random
        rate_limit: proxy başına saniyedeki maksimum istek sayısı
        """
        self.proxies = proxies
        self.algorithm = algorithm
        self.rate_limit = rate_limit
        
        # Dengeleyici durumu
        self.current_index = 0
        self.connections = defaultdict(int)
        self.rate_limiters = {}
        self.metrics = defaultdict(lambda: {
            "total": 0, "success": 0, "failed": 0,
            "response_times": [], "last_check": None
        })
        
        # Rate limiter'ların başlatılması
        for proxy in proxies:
            proxy_url = proxy["url"]
            self.rate_limiters[proxy_url] = TokenBucketRateLimiter(
                rate=rate_limit,
                capacity=rate_limit * 5
            )
        
        self.lock = Lock()
        
        # Arka planda sağlık kontrolü başlatma
        self.health_check_thread = Thread(target=self._health_check_loop, daemon=True)
        self.health_check_thread.start()
    
    def get_next_proxy(self):
        """Algoritmaya göre bir sonraki proxy'yi seçer"""
        with self.lock:
            if self.algorithm == "round_robin":
                return self._round_robin()
            elif self.algorithm == "least_connections":
                return self._least_connections()
            elif self.algorithm == "weighted":
                return self._weighted_random()
            elif self.algorithm == "random":
                return random.choice(self.proxies)["url"]
    
    def _round_robin(self):
        proxy = self.proxies[self.current_index]["url"]
        self.current_index = (self.current_index + 1) % len(self.proxies)
        return proxy
    
    def _least_connections(self):
        min_conn = min(self.connections.values()) if self.connections else 0
        candidates = [p["url"] for p in self.proxies if self.connections[p["url"]] == min_conn]
        return random.choice(candidates)
    
    def _weighted_random(self):
        weights = [p.get("weight", 1) for p in self.proxies]
        return random.choices(self.proxies, weights=weights)[0]["url"]
    
    def make_request(self, url, method="GET", **kwargs):
        """Dengeleyici üzerinden istek yapar"""
        proxy_url = self.get_next_proxy()
        
        # Rate limit'in kullanılabilir olmasını bekle
        self.rate_limiters[proxy_url].wait_and_acquire()
        
        # Bağlantı sayacını artır
        with self.lock:
            self.connections[proxy_url] += 1
        
        try:
            start_time = time.time()
            response = requests.request(
                method,
                url,
                proxies={"http": proxy_url, "https": proxy_url},
                timeout=kwargs.get("timeout", 30),
                **kwargs
            )
            response_time = time.time() - start_time
            
            # Metrikleri kaydet
            self._record_metrics(proxy_url, response_time, True, response.status_code)
            
            return response
        
        except Exception as e:
            self._record_metrics(proxy_url, 0, False, 0)
            raise
        
        finally:
            # Bağlantı sayacını azalt
            with self.lock:
                self.connections[proxy_url] -= 1
    
    def _record_metrics(self, proxy_url, response_time, success, status_code):
        """İstek metriklerini kaydeder"""
        with self.lock:
            m = self.metrics[proxy_url]
            m["total"] += 1
            if success:
                m["success"] += 1
                m["response_times"].append(response_time)
                # Sadece son 1000 değeri sakla
                if len(m["response_times"]) > 1000:
                    m["response_times"].pop(0)
            else:
                m["failed"] += 1
    
    def _health_check_loop(self):
        """Proxy'nin çalışabilirliğini kontrol eden arka plan döngüsü"""
        while True:
            for proxy in self.proxies:
                proxy_url = proxy["url"]
                try:
                    response = requests.get(
                        "http://httpbin.org/ip",
                        proxies={"http": proxy_url},
                        timeout=10
                    )
                    with self.lock:
                        self.metrics[proxy_url]["last_check"] = datetime.now()
                        proxy["status"] = "healthy" if response.status_code == 200 else "unhealthy"
                except:
                    with self.lock:
                        proxy["status"] = "unhealthy"
            
            time.sleep(60)  # Her dakika kontrol et
    
    def get_stats(self):
        """Tüm proxy'ler için istatistikleri döndürür"""
        stats = []
        with self.lock:
            for proxy in self.proxies:
                proxy_url = proxy["url"]
                m = self.metrics[proxy_url]
                
                avg_response_time = (
                    sum(m["response_times"]) / len(m["response_times"])
                    if m["response_times"] else 0
                )
                
                success_rate = (
                    (m["success"] / m["total"] * 100)
                    if m["total"] > 0 else 0
                )
                
                stats.append({
                    "proxy": proxy_url,
                    "status": proxy.get("status", "unknown"),
                    "total_requests": m["total"],
                    "success_rate": round(success_rate, 2),
                    "avg_response_time": round(avg_response_time, 3),
                    "active_connections": self.connections[proxy_url]
                })
        
        return stats

Bu dengeleyiciyi bir pazar yerini taramak için kullanma:

# Dengeleyiciyi ayarlama
proxies = [
    {"url": "http://proxy1.example.com:8080", "weight": 5},
    {"url": "http://proxy2.example.com:8080", "weight": 5},
    {"url": "http://proxy3.example.com:8080", "weight": 3},
    {"url": "http://proxy4.example.com:8080", "weight": 2}
]

balancer = ProxyLoadBalancer(
    proxies=proxies,
    algorithm="weighted",
    rate_limit=60  # Proxy başına dakikada 60 istek
)

# Ürün listesini tarama
product_urls = [f"https://www.wildberries.ru/catalog/{i}/detail.aspx" for i in range(1000)]

results = []
for url in product_urls:
    try:
        response = balancer.make_request(url)
        # Yanıtı işleme
        results.append({"url": url, "status": "success", "data": response.text})
    except Exception as e:
        results.append({"url": url, "status": "error", "error": str(e)})
    
    # Her 100 istekte istatistikleri yazdır
    if len(results) % 100 == 0:
        stats = balancer.get_stats()
        for stat in stats:
            print(f"{stat['proxy']}: {stat['success_rate']}% başarı, "
                  f"{stat['avg_response_time']}s ortalama yanıt")

# Nihai istatistik
print("\n=== Nihai İstatistikler ===")
for stat in balancer.get_stats():
    print(f"{stat['proxy']}:")
    print(f"  Toplam istek: {stat['total_requests']}")
    print(f"  Başarı oranı: {stat['success_rate']}%")
    print(f"  Ortalama yanıt süresi: {stat['avg_response_time']}s")

Node.js için, HTTP istekleri için axios ve istek sıklığını kontrol etmek için node-rate-limiter kütüphaneleri ile benzer bir mimari kullanabilirsiniz:

const axios = require('axios');
const { RateLimiter } = require('limiter');

class ProxyLoadBalancer {
  constructor(proxies, algorithm = 'round_robin', rateLimit = 10) {
    this.proxies = proxies;
    this.algorithm = algorithm;
    this.currentIndex = 0;
    this.connections = new Map();
    this.limiters = new Map();
    this.metrics = new Map();
    
    // Rate limiter'ların başlatılması
    proxies.forEach(proxy => {
      this.limiters.set(proxy.url, new RateLimiter({ 
        tokensPerInterval: rateLimit, 
        interval: 'second' 
      }));
      this.connections.set(proxy.url, 0);
      this.metrics.set(proxy.url, {
        total: 0,
        success: 0,
        failed: 0,
        responseTimes: []
      });
    });
  }
  
  getNextProxy() {
    if (this.algorithm === 'round_robin') {
      const proxy = this.proxies[this.currentIndex].url;
      this.currentIndex = (this.currentIndex + 1) % this.proxies.length;
      return proxy;
    } else if (this.algorithm === 'least_connections') {
      let minConn = Infinity;
      let selectedProxy = null;
      
      this.connections.forEach((count, proxy) => {
        if (count < minConn) {
          minConn = count;
          selectedProxy = proxy;
        }
      });
      
      return selectedProxy;
    }
  }
  
  async makeRequest(url, options = {}) {
    const proxyUrl = this.getNextProxy();
    const limiter = this.limiters.get(proxyUrl);
    
    // Rate limit'in kullanılabilir olmasını bekle
    await limiter.removeTokens(1);
    
    // Bağlantı sayacını artır
    this.connections.set(proxyUrl, this.connections.get(proxyUrl) + 1);
    
    try {
      const startTime = Date.now();
      const response = await axios({
        url,
        proxy: this.parseProxyUrl(proxyUrl),
        timeout: options.timeout || 30000,
        ...options
      });
      
      const responseTime = (Date.now() - startTime) / 1000;
      this.recordMetrics(proxyUrl, responseTime, true);
      
      return response;
    } catch (error) {
      this.recordMetrics(proxyUrl, 0, false);
      throw error;
    } finally {
      this.connections.set(proxyUrl, this.connections.get(proxyUrl) - 1);
    }
  }
  
  parseProxyUrl(proxyUrl) {
    const url = new URL(proxyUrl);
    return {
      host: url.hostname,
      port: parseInt(url.port)
    };
  }
  
  recordMetrics(proxyUrl, responseTime, success) {
    const m = this.metrics.get(proxyUrl);
    m.total++;
    
    if (success) {
      m.success++;
      m.responseTimes.push(responseTime);
      if (m.responseTimes.length > 1000) {
        m.responseTimes.shift();
      }
    } else {
      m.failed++;
    }
  }
  
  getStats() {
    const stats = [];
    
    this.proxies.forEach(proxy => {
      const m = this.metrics.get(proxy.url);
      const avgResponseTime = m.responseTimes.length > 0
        ? m.responseTimes.reduce((a, b) => a + b, 0) / m.responseTimes.length
        : 0;
      
      const successRate = m.total > 0 ? (m.success / m.total * 100) : 0;
      
      stats.push({
        proxy: proxy.url,
        totalRequests: m.total,
        successRate: successRate.toFixed(2),
        avgResponseTime: avgResponseTime.toFixed(3),
        activeConnections: this.connections.get(proxy.url)
      });
    });
    
    return stats;
  }
}

// Kullanım
const proxies = [
  { url: 'http://proxy1.example.com:8080', weight: 5 },
  { url: 'http://proxy2.example.com:8080', weight: 5 }
];

const balancer = new ProxyLoadBalancer(proxies, 'round_robin', 60);

async function parseProducts() {
  const urls = Array.from({ length: 1000 }, (_, i) => 
    `https://www.wildberries.ru/catalog/${i}/detail.aspx`
  );
  
  for (const url of urls) {
    try {
      const response = await balancer.makeRequest(url);
      console.log(`Başarı: ${url}`);
    } catch (error) {
      console.error(`Hata: ${url} - ${error.message}`);
    }
  }
  
  console.log('\n=== İstatistikler ===');
  console.log(balancer.getStats());
}

parseProducts();

Belirli görevler için optimizasyon: tarama, API, otomasyon

Farklı görevler, farklı yük dengeleme stratejileri gerektirir. Pazar yerlerini (Wildberries, Ozon, Avito) taramak için, istek sayısına ve coğrafi dağılıma göre döngü stratejisi en uygunudur. Farklı Rus şehirlerinden ikamet eden proxy'ler kullanın, her 50-100 istekte bir proxy değiştirin, istekler arasında rastgele gecikmeler (1-3 saniye) ekleyin, böylece insan davranışını taklit edersiniz.

Sosyal medya API'leri (Instagram, Facebook, VK) ile çalışırken, bir oturum çerçevesinde IP adresinin kararlılığı kritik öneme sahiptir. IP Hash algoritmasını veya sticky sessions kullanın: bir hesabın tüm istekleri her zaman aynı proxy üzerinden gitmelidir. Bu, coğrafi konum değişikliğinin şüpheli görünmesini önler ve hesap engellemesini azaltır. Mobil proxy'ler önerilir, çünkü sosyal medya platformları mobil IP'lere daha fazla güvenmektedir.

# Instagram için sticky sessions örneği
class StickySessionBalancer:
    def __init__(self, proxies):
        self.proxies = proxies
        self.session_map = {}  # {account_id: proxy_url}
        self.proxy_usage = defaultdict(int)
    
    def get_proxy_for_account(self, account_id):
        """Hesap için sabit bir proxy döndürür"""
        if account_id in self.session_map:
            return self.session_map[account_id]
        
        # En az yüklenmiş proxy'yi seç
        proxy = min(self.proxies, key=lambda p: self.proxy_usage[p])
        self.session_map[account_id] = proxy
        self.proxy_usage[proxy] += 1
        
        return proxy
    
    def release_account(self, account_id):
        """Hesapla çalışmayı bitirdiğinde proxy'yi serbest bırakır"""
        if account_id in self.session_map:
            proxy = self.session_map[account_id]
            self.proxy_usage[proxy] -= 1
            del self.session_map[account_id]

Bu, Instagram için sticky sessions örneğidir.

```