← Bloga geri dön

Kereviz, RQ veya BullMQ: Proxy ile Görev Kuyruğu Nasıl Oluşturulur ve IP Başına İstek Limiti Nasıl Aşılır

Celery, RQ ve BullMQ'da proxy döngüsü ile görev kuyruklarının mimarisini inceliyoruz - IP adresleri arasında yükü nasıl dağıtacağımızı ve rate limit'ten nasıl kaçınacağımızı.

📅20 Ekim 2026

Bir parser veya bot, tek bir IP'den dakikada yüzlerce istek gönderdiğinde, sunucu hızla rate limit'i devreye alır ve sonrasında CAPTCHA veya yasaklama gelir. Çözüm, istekleri işçiler ve proxy'ler arasında dağıtan bir görev kuyruğudur. Bu yazıda, Celery, RQ ve BullMQ'da böyle bir mimarinin nasıl çalıştığını ve her IP adresi için istek limitini nasıl etkili bir şekilde yönetebileceğimizi inceleyeceğiz.

Proxy ile çalışırken neden görev kuyruğu?

Eğer görev, Wildberries'den 50.000 ürün kartını çekmek veya 10.000 Instagram hesabının durumunu kontrol etmekse, ardışık isteklerin başlatılması saatler alır ve kontrolsüz paralel başlatma, IP'nin yasaklanmasına neden olur. Görev kuyruğu (task queue), her iki sorunu da çözer: büyük bir iş yükünü küçük görevlere ayırır, bunları birkaç işçi arasında dağıtır ve her işçiye ayrı bir proxy bağlamaya olanak tanır.

Mimari genellikle şöyle görünür: mesaj aracısı (Redis veya RabbitMQ) görev kuyruğunu saklar, işçiler kuyruğundan görevleri alır ve bunları yerine getirir, her işçi kendi proxy'sini kullanır veya havuzdan proxy'leri döndürür. Bu, her IP üzerindeki yükü güvenli sınırlar içinde tutmaya olanak tanır, hatta toplam istek hacmi büyük olsa bile.

Bu yaklaşım yalnızca parser geliştiricileri tarafından değil, aynı zamanda Facebook Ads reklam panellerinin kontrolünü otomatikleştiren ekipler, Ozon'daki fiyatları izleyenler veya aynı anda onlarca web sitesinden veri toplayanlar tarafından da kullanılmaktadır. Kuyruk ve IP'ye göre akıllı dağıtım olmadan, böyle bir sistemin ilk iş gününde engellenmesi kaçınılmazdır.

Tek bir IP üzerindeki istek limitinin sorunu

Çoğu web sitesi ve API, aşırı yüklenmeye karşı koruma sağlar. Bu, çeşitli şekillerde ifade edilebilir: sunucu HTTP 429 (Too Many Requests) döner, CAPTCHA gösterir, IP'yi 10-60 dakika süreyle geçici olarak yasaklar veya kalıcı olarak kara listeye alır. Farklı platformlarda limitler büyük ölçüde değişir — örneğin, Wildberries API, bir adresten saniyede sınırlı sayıda isteğe izin verirken, Instagram, ardışık 15-20 eylemden sonra şüpheli aktiviteye yanıt verir.

Kuyruğun inşasındaki en büyük hata, tüm işçileri aynı IP üzerinden başlatmaktır. Görevler 20 işçi arasında dağıtılmış olsa bile, hepsi aynı proxy'yi kullanıyorsa veya hiç kullanmıyorsa, bu IP üzerindeki limit, ardışık yürütme durumundaki kadar hızlı bir şekilde devreye girecektir. Bu nedenle, işçi sayısı, proxy havuzundaki mevcut IP adresi sayısıyla orantılı olmalıdır.

Tek bir alan adına yüksek istek sıklığı olan görevler için veri merkezi proxy'leri kullanmak daha iyidir — bunlar düşük gecikme süresi sağlar ve hızın önemli olduğu, sıradan bir kullanıcı gibi görünmenin değil, ölçeklenebilir paralel çekim için uygundur. Eğer amaç, pazaryerleri veya sosyal medya gibi daha katı korumaları aşmaksa, sıradan kullanıcılar gibi görünen IP'lere ihtiyaç vardır; yani, konut veya mobil IP'ler.

Celery: mimari ve kodda proxy rotasyonu

Celery, Python ekosisteminde en olgun ve popüler görev kuyruğudur. Bir aracının (genellikle Redis veya RabbitMQ) üzerinde çalışır ve eşzamanlılık, yeniden deneme ve görev öncelikleri için esnek bir yapılandırma desteği sunar. Proxy rotasyonu için, IP havuzunu Redis'te saklamak ve her göreve kuyrukta atanacak proxy'yi belirlemek oldukça kullanışlıdır.

from celery import Celery
import requests
import redis
import random

app = Celery('tasks', broker='redis://localhost:6379/0')
redis_client = redis.Redis(host='localhost', port=6379, db=1)

PROXY_POOL = [
    "http://user:[email protected]:8000",
    "http://user:[email protected]:8000",
    "http://user:[email protected]:8000",
]

def get_proxy():
    # Redis üzerinden round-robin, tek bir IP'ye yük bindirmemek için
    idx = redis_client.incr("proxy_cursor") % len(PROXY_POOL)
    return PROXY_POOL[idx]

@app.task(bind=True, max_retries=3, default_retry_delay=30)
def fetch_url(self, url):
    proxy = get_proxy()
    try:
        response = requests.get(
            url,
            proxies={"http": proxy, "https": proxy},
            timeout=15
        )
        if response.status_code == 429:
            raise self.retry(exc=Exception("Rate limited"))
        return response.status_code
    except requests.exceptions.RequestException as exc:
        raise self.retry(exc=exc)

Anahtar nokta, get_proxy() fonksiyonudur; bu fonksiyon, Redis sayacını kullanarak havuzdan sıradaki proxy'yi döndürür. Bu, yükün tüm IP'ler arasında eşit şekilde dağıtılmasını garanti eder ve tek bir IP üzerinde yoğunlaşmasını önler. max_retries parametresi ve 429 kodunun işlenmesi, mevcut IP'nin kısıtlandığı durumlarda görevin otomatik olarak başka bir proxy ile yeniden gönderilmesine olanak tanır.

Celery, işçi düzeyinde eşzamanlılık kontrolü için, işçi başlatılırken --concurrency parametresi ile aynı anda yürütülen görev sayısını sınırlamaya olanak tanır ve ayrıca farklı önceliklere sahip kuyruklar aracılığıyla (örneğin, katı rate limit olan yavaş görevler için ayrı bir kuyruk) yapılabilir.

RQ (Redis Queue): basit bir alternatif

RQ, Celery'den daha hafif bir kütüphanedir, RabbitMQ aracısı olmadan ve minimum yapılandırma ile çalışır. Küçük bir proje için uygundur ve karmaşık görev yönlendirmesi gerektirmiyorsa, sadece işçilerle birlikte bir kuyruk ve göreve proxy bağlama imkanı sunar.

from redis import Redis
from rq import Queue
import requests
import itertools

redis_conn = Redis()
q = Queue(connection=redis_conn)

PROXY_POOL = [
    "http://user:[email protected]:8000",
    "http://user:[email protected]:8000",
]
proxy_cycle = itertools.cycle(PROXY_POOL)

def fetch_with_proxy(url):
    proxy = next(proxy_cycle)
    response = requests.get(
        url,
        proxies={"http": proxy, "https": proxy},
        timeout=15
    )
    if response.status_code == 429:
        # Gecikmeli olarak kuyruğa yeniden ekleme
        q.enqueue_in(60, fetch_with_proxy, url)
        return None
    return response.status_code

# Görevleri kuyruğa ekleme
urls = ["https://example.com/page1", "https://example.com/page2"]
for url in urls:
    q.enqueue(fetch_with_proxy, url)

RQ'da itertools.cycle ile rotasyon, işçi süreci içinde çalışır — bu, Redis sayacından daha basittir, ancak çok sayıda paralel işçi olduğunda daha kötü ölçeklenir, çünkü her işçi döngüyü baştan başlatır. 1-5 işçi ile küçük projeler için bu yeterlidir, daha büyük projeler için Celery örneğindeki gibi Redis'te merkezi bir sayaç kullanmaya geri dönmek daha iyidir.

RQ, projede zaten Redis kullanan geliştiriciler için iyi bir seçenektir ve ayrı bir mesaj aracısı kurmak istemezler. Dezavantajı, Celery ile karşılaştırıldığında daha az yerleşik önceliklendirme ve izleme mekanizmasına sahip olmasıdır, bu nedenle günde yüz binlerce görev içeren üretim sistemleri için genellikle Celery tercih edilir.

BullMQ: IP sınırlı Node.js kuyruğu

BullMQ, Node.js ekosisteminde görev kuyrukları için bir standarttır, Redis üzerine inşa edilmiştir ve IP üzerindeki istek limitini kontrol etmek için yerleşik bir rate limiter'a sahiptir. İstekleri manuel olarak saymak yerine, limiti doğrudan kuyruk seviyesinde belirtebilirsiniz.

const { Queue, Worker } = require('bullmq');
const axios = require('axios');

const connection = { host: 'localhost', port: 6379 };

const proxyPool = [
  'http://user:[email protected]:8000',
  'http://user:[email protected]:8000',
  'http://user:[email protected]:8000',
];

const queue = new Queue('fetchQueue', { connection });

// Limiter: kuyruk başına saniyede en fazla 5 görev
const worker = new Worker('fetchQueue', async job => {
  const proxy = proxyPool[job.id % proxyPool.length];
  try {
    const response = await axios.get(job.data.url, {
      proxy: false,
      httpsAgent: new (require('https-proxy-agent'))(proxy),
      timeout: 15000,
    });
    return response.status;
  } catch (err) {
    if (err.response && err.response.status === 429) {
      throw new Error('Rate limited, retrying with another proxy');
    }
    throw err;
  }
}, {
  connection,
  limiter: { max: 5, duration: 1000 },
  concurrency: proxyPool.length,
});

for (let i = 0; i < 100; i++) {
  queue.add('fetch', { url: `https://example.com/item/${i}` }, {
    attempts: 3,
    backoff: { type: 'exponential', delay: 5000 },
  });
}

BullMQ'daki limiter parametresi, belirli bir zaman diliminde işlenen toplam görev sayısını sınırlayan yerleşik bir mekanizmadır; bu, sistem genelinde istek limitini korumak için kullanışlıdır. concurrency parametresi, proxy havuzunun boyutuna eşit olup, aynı anda çalışacak işçi sayısının tam olarak mevcut IP sayısı kadar olmasını garanti eder.

Bu yaklaşım, TikTok veya Telegram'da otomatik eylemler için kendi botlarını yazan ekipler tarafından sıkça kullanılmaktadır — BullMQ, diğer Node.js yığını ile iyi entegrasyon sağlar ve tek bir görev için Python'a geçiş yapmayı gerektirmez.

Celery, RQ ve BullMQ karşılaştırması

Parametre Celery RQ BullMQ
Dil Python Python Node.js
Aracı Redis / RabbitMQ Sadece Redis Sadece Redis
Yerleşik rate limiter Yok (manuel yazılır) Yok Evet, kutudan çıkmış olarak
Giriş eşiği Orta Düşük Orta
Uygun olduğu yerler Büyük üretim sistemleri Küçük projeler, prototipler Node.js yığını, botlar, otomasyon

IP'ye göre yük dağıtım stratejileri

Yukarıdaki örneklerde kullanılan round-robin, en basit stratejidir, ancak her zaman en iyi seçenek değildir. İşe göre dikkate almanız gereken birkaç alternatif:

  • Round-robin — her bir sonraki istek, sıradaki proxy üzerinden döner. Tüm IP'ler eşit olduğunda ve limitler aynı olduğunda uygundur.
  • Sticky session — bir proxy, belirli bir hesap veya oturum için tüm çalışma süresi boyunca sabitlenir. Sosyal medya ve pazaryerleri için kritik öneme sahiptir; çünkü oturum ortasında IP değişikliği şüpheli görünür.
  • Ağırlıklı dağıtım — bazı istekler daha pahalı ve güvenilir IP'lere (örneğin, mobil) yönlendirilirken, bazıları ucuz veri merkezi IP'lerine yönlendirilir; hangi alan adının işlendiğine bağlı olarak.
  • Adaptive throttling — görev gönderim hızı, 429 hata oranı veya CAPTCHA oranı arttığında otomatik olarak düşer ve hatalar kaybolduğunda tekrar yükselir.

Canlı bir kullanıcı gibi görünmenin önemli olduğu görevler için — örneğin, Instagram veya TikTok hesaplarının ısıtılması ve kontrolü gibi — mobil proxy'ler ile sticky session uygulamak daha iyidir: bunlar, anti-bot sistemleri tarafından daha az şüpheli görünür ve mobil internet kullanıcıları gibi davranır.

Hız ve hacmin önemli olduğu, algoritmanın güvenilirliğinden ziyade, web sitelerinden veri toplamak için round-robin ile konut proxy'leri kullanmak, stabilite ve fiyat arasında bir denge sağlar: IP'ler gerçek kullanıcılar gibi görünür, ancak belirli bir oturum için riske girmeden sık sık değiştirilebilir.

Hata 429 ve yasaklamaların izlenmesi

Görev kuyruğu, izleme olmadan bir kara kutudur: bazı görevlerin neden başarısız olduğunu ve hangi IP'lerin şüpheli olduğunu anlamak zordur. İzlenmesi gereken minimum metrik seti:

  • Her proxy için ayrı ayrı 429 ve 403 kodlu yanıtların yüzdesi
  • Ortalama yanıt süresi — gecikmedeki artış genellikle yasaklamadan önce gelir
  • Görev başına yeniden deneme (retries) sayısı
  • Gerçek zamanlı görev kuyruğu uzunluğu — eğer bu artıyorsa, işçiler başa çıkamıyor demektir

Celery'de bunun için Flower kullanmak oldukça uygundur — gerçek zamanlı görevler ve işçilerin izlenmesi için bir web arayüzüdür. BullMQ'da benzer işlevselliğe sahip Bull Board bulunmaktadır. RQ için RQ Dashboard mevcuttur. Üç araç da görevlerin durumunu, başarısız deneme sayısını gösterir ve havuzdan hangi proxy'nin geçici olarak rotasyondan çıkarılması gerektiğini hızlı bir şekilde anlamanıza olanak tanır.

İyi bir uygulama, birkaç ardışık 429 hatasından sonra proxy'yi "karantinada" olarak 15-30 dakika işaretlemektir ve başarılı bir test isteğinden sonra havuza geri döndürmektir. Bu, yasaklanan IP'nin görev almaya devam etmesini ve işçilerin zamanını boşa harcamasını önler.

Sonuç

Görev kuyruğu, isteklerin ölçeklenmesi sorununu çözer, ancak IP üzerindeki limitlerden korunmak için etkili bir proxy rotasyonu gereklidir — bu, Celery, RQ veya BullMQ içinde düşünülmelidir. Araç seçimi, yığın yapısına bağlıdır: Python projeleri genellikle üretim için Celery'yi ve basit görevler için RQ'yu tercih ederken, Node.js geliştiricileri — yerleşik rate limiter ile BullMQ'yu tercih eder.

Seçilen kuyruktan bağımsız olarak, sonuç, proxy havuzunun kalitesine büyük ölçüde bağlıdır. Hedef hızlı toplu bir çekimse, hız için veri merkezi proxy'lerine göz atın; sosyal medya ve pazaryerleri ile çalışırken, anti-bot sistemlerinin sadakatinin önemli olduğu durumlarda, konut veya mobil IP'ler uygundur — bunlar 429 hata ve yasaklama oranını azaltır, bu da doğrudan yeniden deneme sayısını azaltır ve tüm görev kuyruğunun yürütülmesini hızlandırır.