Tek bir worker süreci saniyede yalnızca sınırlı sayıda CAPTCHA çözüm isteğini işleyebilir; istek hacminiz büyüdüğünde çözüm, trafiği birden fazla worker'a dağıtan bir yük dengeleyicidir. Kısa cevap: değişken çözüm süreleri nedeniyle CAPTCHA iş yükleri için en doğru yönlendirme stratejisi en az bağlantıdır (least connections). Bu rehber worker'ları NGINX arkasında nasıl konumlandıracağınızı, hangi stratejinin ne zaman işe yaradığını ve sağlık kontrollerini üretimde nasıl kuracağınızı adım adım gösterir.
Mimarinin genel görünümü
Yük dengeleyici, scraper'lardan gelen çözüm isteklerini bir worker havuzuna dağıtır; her worker CaptchaAI API'sine bağımsız olarak istek gönderir. Böylece tek bir sürecin darboğaza dönüşmesini önler ve verimi worker sayısıyla birlikte artırırsınız.
Mimari üç katmandan oluşur:
- Scraper'lar: çözüm isteklerini üreten istemciler.
- Yük dengeleyici: istekleri sağlıklı worker'lara dağıtan katman.
- Worker'lar: CaptchaAI API'sine görev gönderip sonucu sorgulayan süreçler.
[Scraper 1] ──┐ ┌── [Worker 1] ──→ CaptchaAI API
[Scraper 2] ──┤── [Load Balancer] ──┤── [Worker 2] ──→ CaptchaAI API
[Scraper 3] ──┘ └── [Worker 3] ──→ CaptchaAI API
Yönlendirme stratejileri karşılaştırması
Hangi stratejinin iş yükünüze uyduğuna en baştan karar verin:
| Strateji | Nasıl çalışır? | En uygun senaryo |
|---|---|---|
| Round-robin | Sırayla dağıtım | Eşit kapasiteli worker'lar |
| En az bağlantı | En az yüklü worker'a yönlendirme | CAPTCHA çözme (değişken görev süresi) |
| Ağırlıklı | Ağırlıkla orantılı | Karma kapasiteli worker'lar |
| IP karması | Aynı istemci – aynı worker | Oturum benzeşimi gerektiğinde |
| Rastgele | Rastgele seçim | Basit, eşit dağıtılmış yük |
Öneri: CAPTCHA çözümü için en az bağlantı stratejisini kullanın. Görev süreleri 5 saniye ile 120 saniye arasında değiştiği için round-robin bazı worker'ları boşta bırakırken diğerlerini aşırı yükler. Oturum benzeşimi (session affinity) gerektiren bir hedefiniz yoksa IP karması stratejisine ihtiyacınız olmaz — CAPTCHA çözüm istekleri durum bilgisizdir.
NGINX yapılandırması
NGINX, worker havuzunun önünde ters proxy ve yük dengeleyici olarak çalışır. Aşağıdaki üç yapılandırma, aynı worker kümesi için üç farklı yönlendirme davranışı gösterir.
Round-robin (varsayılan)
İstekleri worker'lara sırayla dağıtır. Worker'lar eşit kapasitedeyse ve çözüm süreleri birbirine yakınsa yeterlidir; ancak CAPTCHA çözüm süreleri değişken olduğundan tek başına genellikle eşit olmayan yük üretir.
upstream captcha_workers {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
server {
listen 80;
server_name captcha.internal;
location /solve {
proxy_pass http://captcha_workers;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10s;
proxy_read_timeout 300s; # CAPTCHA solving can take minutes
}
location /health {
proxy_pass http://captcha_workers;
proxy_connect_timeout 5s;
proxy_read_timeout 5s;
}
}
En az bağlantı (CAPTCHA çözümü için önerilen)
Her yeni isteği o an en az aktif bağlantıya sahip worker'a yönlendirir. Çözüm süreleri 5 saniye ile 120 saniye arasında değiştiğinden, uzun süren bir görev bir worker'ı meşgul ederken yeni istekler boştaki worker'lara gider. weight=2 ile daha yüksek kapasiteli bir worker'a orantılı olarak daha fazla trafik verebilirsiniz.
upstream captcha_workers {
least_conn; # Route to worker with fewest active connections
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080 weight=2; # Higher capacity worker
# Health checks
server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;
}
Yedek worker'larla
backup işaretli worker yalnızca birincil worker'ların tümü devre dışı kaldığında devreye girer. Sıcak yedek (hot standby) kapasitesi için idealdir.
upstream captcha_workers {
least_conn;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080 backup; # Only used when others are down
}
Worker API sunucusu
Her worker, yük dengeleyiciden /solve isteğini alır, CaptchaAI API'sine görevi gönderir ve sonucu sorgular. /health uç noktası ise anlık yükü bildirerek yük dengeleyicinin aşırı yüklenmiş worker'ları geçici olarak devre dışı bırakmasını sağlar.
Python (Flask)
Eşzamanlı görev sayısını bir kilit (lock) ile izleyen, kapasite dolduğunda 503 WORKER_AT_CAPACITY döndüren örnek bir worker:
import os
import time
import threading
import requests
from flask import Flask, request, jsonify
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
app = Flask(__name__)
# Track active tasks for load reporting
active_tasks = 0
tasks_lock = threading.Lock()
max_concurrent = int(os.environ.get("MAX_CONCURRENT", "20"))
@app.route("/solve", methods=["POST"])
def solve():
global active_tasks
with tasks_lock:
if active_tasks >= max_concurrent:
return jsonify({"error": "WORKER_AT_CAPACITY"}), 503
active_tasks += 1
try:
data = request.json
result = solve_captcha(data)
return jsonify(result)
finally:
with tasks_lock:
active_tasks -= 1
@app.route("/health")
def health():
with tasks_lock:
load = active_tasks / max_concurrent
return jsonify({
"status": "healthy" if load < 0.9 else "overloaded",
"active_tasks": active_tasks,
"max_concurrent": max_concurrent,
"load_pct": round(load * 100, 1)
}), 200 if load < 0.9 else 503
def solve_captcha(data):
session = requests.Session()
payload = {
"key": API_KEY,
"method": data.get("method", "userrecaptcha"),
"googlekey": data.get("sitekey"),
"pageurl": data.get("pageurl"),
"json": 1
}
if data.get("proxy"):
payload["proxy"] = data["proxy"]
payload["proxytype"] = data.get("proxytype", "HTTP")
resp = session.post("https://ocr.captchaai.com/in.php", data=payload)
result = resp.json()
if result.get("status") != 1:
return {"error": result.get("request")}
captcha_id = result["request"]
for _ in range(60):
time.sleep(5)
poll = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if poll.get("status") == 1:
return {"solution": poll["request"], "captcha_id": captcha_id}
if poll.get("request") != "CAPCHA_NOT_READY":
return {"error": poll.get("request")}
return {"error": "TIMEOUT"}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080, threaded=True)
JavaScript (Express)
Aynı worker mantığının Node.js karşılığı — Axios ile aynı gönder-ve-sorgula döngüsünü kullanır:
const express = require("express");
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
const MAX_CONCURRENT = parseInt(process.env.MAX_CONCURRENT || "20", 10);
const PORT = parseInt(process.env.PORT || "8080", 10);
let activeTasks = 0;
const app = express();
app.use(express.json());
app.post("/solve", async (req, res) => {
if (activeTasks >= MAX_CONCURRENT) {
return res.status(503).json({ error: "WORKER_AT_CAPACITY" });
}
activeTasks++;
try {
const result = await solveCaptcha(req.body);
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
} finally {
activeTasks--;
}
});
app.get("/health", (req, res) => {
const load = activeTasks / MAX_CONCURRENT;
const status = load < 0.9 ? "healthy" : "overloaded";
res
.status(load < 0.9 ? 200 : 503)
.json({ status, activeTasks, maxConcurrent: MAX_CONCURRENT, loadPct: Math.round(load * 100) });
});
async function solveCaptcha(data) {
const submitResp = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: {
key: API_KEY,
method: data.method || "userrecaptcha",
googlekey: data.sitekey,
pageurl: data.pageurl,
json: 1,
},
});
if (submitResp.data.status !== 1) {
return { error: submitResp.data.request };
}
const captchaId = submitResp.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const pollResp = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (pollResp.data.status === 1) {
return { solution: pollResp.data.request, captchaId };
}
if (pollResp.data.request !== "CAPCHA_NOT_READY") {
return { error: pollResp.data.request };
}
}
return { error: "TIMEOUT" };
}
app.listen(PORT, () => console.log(`Worker listening on port ${PORT}`));
İstemci tarafı yük dengeleme
Ayrı bir yük dengeleyici (NGINX, HAProxy) kuramadığınız durumlarda yönlendirmeyi doğrudan istemci kodunda uygulayabilirsiniz. Aşağıdaki sınıf, sağlıklı worker'lar arasından en az yüklü olanı seçer ve bir worker 503 döndürdüğünde ya da yanıt vermediğinde görevi otomatik olarak başka bir worker'a yeniden yönlendirir:
import random
import requests
class ClientLoadBalancer:
def __init__(self, workers):
self.workers = [
{"url": url, "healthy": True, "active": 0}
for url in workers
]
def get_worker(self):
healthy = [w for w in self.workers if w["healthy"]]
if not healthy:
raise Exception("No healthy workers")
return min(healthy, key=lambda w: w["active"])
def solve(self, task):
worker = self.get_worker()
worker["active"] += 1
try:
resp = requests.post(
f"{worker['url']}/solve",
json=task,
timeout=300
)
if resp.status_code == 503:
worker["healthy"] = False
return self.solve(task) # Retry on another worker
return resp.json()
except requests.RequestException:
worker["healthy"] = False
return self.solve(task)
finally:
worker["active"] -= 1
lb = ClientLoadBalancer([
"http://10.0.1.10:8080",
"http://10.0.1.11:8080",
"http://10.0.1.12:8080"
])
result = lb.solve({"sitekey": "6Le-wvkS...", "pageurl": "https://example.com"})
Strateji seçim rehberi
- Round-robin: Worker'lar homojen olduğunda ve çözüm süreleri dar bir bantta kaldığında yeterlidir.
- En az bağlantı: Çözüm süreleri değişkenken ve uzun görevler tek bir worker'ı meşgul edebiliyorken varsayılan tercihiniz olsun.
- Ağırlıklı yönlendirme: Worker'larınız farklı kapasitelere sahipse (
weight) kullanın. - IP karması / yedek yönlendirme: Yalnızca oturum benzeşimi ya da hata izolasyonu gereken hedefler için ayırın.
Worker eşzamanlılığını thread planınızla eşleştirme
Yük dengeleyicinin ötesinde sıkça göz ardı edilen bir sınır vardır: CaptchaAI planınızın thread sayısı. CaptchaAI çözüm başına değil eşzamanlı thread başına ücretlendirir ve her plan thread başına sınırsız çözüm içerir. Bir thread, o an işlenen tek bir CAPTCHA demektir.
Tüm worker'larınızdaki MAX_CONCURRENT değerlerinin toplamı planınızın thread sayısını aşmamalıdır. Örneğin her biri MAX_CONCURRENT=20 ile çalışan üç worker toplam 60 eşzamanlı görev üretir; bu, ADVANCE ($90/ay, 50 thread) planının 50 thread sınırını aşar ve fazla istekler API tarafında kuyruğa girer. Bu durumda ya worker başına eşzamanlılığı düşürün ya da PREMIUM ($170/ay, 100 thread) gibi daha yüksek bir plana geçin. Thread tabanlı USD fiyatlandırması, eşzamanlılığı öngörülebilir bir aylık maliyete bağladığı için kapasite planlamasını kolaylaştırır.
Yerel senaryo: e-ticaret QA ekibi
Türkiye'deki bir e-ticaret ekibinin, ödeme adımı (checkout) ve giriş akışlarını Europe/Istanbul saat diliminde gece toplu olarak doğruladığını düşünün. QA test akışları kısa sürede yüzlerce reCAPTCHA doğrulaması üretir; tek bir worker bu ani yükü kaldıramaz. En az bağlantı stratejisiyle üç worker'a dağıtılan trafik, uzun süren çözümlerin kısa olanları bloke etmesini önler. Test sırasında kişisel veri içeren sayfalar toplanıyorsa, bu verinin KVKK kapsamında olduğunu ve yalnızca yetkili QA/veri toplama iş akışlarında işlenmesi gerektiğini unutmayın.
Sağlık kontrolleri ve gözlemlenebilirlik
/health uç noktasının yalnızca "ayakta mı" değil, "kapasitede mi" bilgisini de döndürmesi kritiktir. Yukarıdaki worker, yük %90'ı aştığında 503 döndürerek yük dengeleyicinin o worker'a yeni istek göndermesini durdurur. Üretimde ayrıca şu metrikleri izleyin: worker başına aktif görev sayısı, çözüm başarı oranı, ortalama çözüm süresi ve 503/TIMEOUT yanıtlarının sıklığı. Bu metrikler, bir worker'ı büyütmeniz mi yoksa havuzu yatay olarak genişletmeniz mi gerektiğini net biçimde gösterir.
Sorun giderme
| Sorun | Sebep | Çözüm |
|---|---|---|
| 502 Bad Gateway | Worker çöktü veya hiç başlatılmadı | Worker günlüklerini inceleyin; port bağlamasını (port binding) doğrulayın |
| Düzensiz yük dağılımı | Değişken görev süreleriyle round-robin | En az bağlantı stratejisine geçin |
| Sağlık kontrolü yanlış pozitif veriyor | Kontrol geçiyor ama worker kapasitede | /health yanıtına yük yüzdesini ekleyin |
| Bağlantı zaman aşımı | proxy_read_timeout çok kısa |
CAPTCHA çözümü için 300 saniye veya üzerine ayarlayın |
Sık sorulan sorular
CAPTCHA çözüm worker'ları için hangi yönlendirme stratejisi en iyisidir?
En az bağlantı (least connections). Çözüm süreleri görevden göreve büyük ölçüde değiştiği için, isteği o an en az meşgul worker'a yönlendirmek yükü round-robin'den çok daha dengeli dağıtır.
Toplam MAX_CONCURRENT değerim planımın thread sayısını aşarsa ne olur?
Fazla istekler CaptchaAI tarafında kuyruğa girer ve çözüm süreleri uzar. Tüm worker'larınızdaki eşzamanlılık toplamını planınızın thread sayısıyla (ör. ADVANCE'te 50 thread) hizalayın veya daha yüksek bir plana geçin.
Yapışkan oturum (sticky session) kullanmalı mıyım?
Hayır. CAPTCHA çözüm istekleri durum bilgisizdir; herhangi bir worker herhangi bir görevi işleyebilir. Yapışkan oturumlar yalnızca eşit olmayan yük dağılımına yol açar.
Bir worker çöktüğünde trafik otomatik yeniden yönlendirilir mi?
Evet. NGINX'te max_fails ve fail_timeout ayarları çöken worker'ı havuzdan çıkarır; istemci tarafı yük dengelemede ise 503 veya bağlantı hatası alan görev başka bir worker'a yeniden gönderilir.
proxy_read_timeout değerini kaça ayarlamalıyım?
Uzun süren çözümlerin kesilmemesi için en az 300 saniye. Çözüm süresi tek bir CAPTCHA'da 120 saniyeye kadar çıkabildiğinden, daha kısa bir zaman aşımı geçerli çözümleri boşa harcar.
İlgili makaleler
- CaptchaAI callback ve hata yönetimi desenleri
- Node.js ve Puppeteer ile gelişmiş CaptchaAI desenleri
- Yüksek hacimli CAPTCHA çözme mimari desenleri
Sonraki adımlar
Çözüm veriminizi ölçeklendirmeye hazır mısınız? CaptchaAI API anahtarınızı alın ve worker'larınızı bir yük dengeleyici arkasında yayına alın.
İlgili kılavuzlar: