DevOps & Scaling

Prometheus ve Grafana ile CAPTCHA Çözme Oranlarını İzleme

Çözüm oranınızın düştüğünü müşteri şikayetinden önce görmek istiyorsanız cevap tek satır: metrikleri Prometheus'a yazın, Grafana'da izleyin ve eşik aşıldığında uyarı alın. Panelsiz bir çözücü sorunu ancak istekler düşünce fark eder — bu da saatlerce sessiz kayıp demektir.

İstanbul'da teslim tarihine yetişen bir otomasyon geliştiricisi için, birçok worker aynı anda çözüm yaparken hangi türün yavaşladığını ve bakiyenin ne zaman biteceğini görmek şarttır.


Neyi neden izlemeliyiz?

Bir çözücünün sağlığı şu beş metrikte özetlenir:

Metrik Tür Amaç
captcha_solves_total Sayaç Toplam çözüm denemeleri
captcha_solves_success Sayaç Başarılı çözümler
captcha_solves_errors Sayaç Başarısız çözümler (hata türüne göre)
captcha_solve_duration Histogram Çözüm süresinin dağılımı
captcha_balance Ölçer Cari hesap bakiyesi
captcha_queue_length Ölçer Kuyrukta bekleyen görevler

Bu altı metrik birlikte iki soruyu yanıtlar: sistem şu anda sağlıklı mı ve yakında bozulacak mı? captcha_solves_success / captcha_solves_total oranı anlık başarıyı verir; captcha_solves_errors etiketli dökümü kök nedeni işaret eder. captcha_solve_duration histogramı yavaşlamayı ortalamada gizlenmeden gösterir, captcha_balance ise boru hattı bakiye bitince sessizce durmadan önce sizi uyarır.

Pratikte panelinizi şu üç soruya göre kurun:

  • Başarı oranı düşüyor mu? — success / total oranı.
  • Yavaşlama tek bir türde mi toplanıyor? — duration, method etiketiyle.
  • Bakiye ne zaman bitecek? — balance eğilimi.

Python ile metrik toplayıcı

Çözücünüzü prometheus_client ile sarmalayın; her çağrı denemeyi, sonucu ve süreyi kaydeder ve /metrics uç noktası bunları yayınlar.

# metrics.py
import time
import requests
from prometheus_client import (
    Counter, Histogram, Gauge, start_http_server,
)


# Define metrics
SOLVES_TOTAL = Counter(
    "captcha_solves_total",
    "Total CAPTCHA solve attempts",
    ["method"],
)

SOLVES_SUCCESS = Counter(
    "captcha_solves_success",
    "Successful CAPTCHA solves",
    ["method"],
)

SOLVES_ERRORS = Counter(
    "captcha_solves_errors",
    "Failed CAPTCHA solves",
    ["method", "error_code"],
)

SOLVE_DURATION = Histogram(
    "captcha_solve_duration_seconds",
    "CAPTCHA solve duration in seconds",
    ["method"],
    buckets=[5, 10, 15, 20, 30, 45, 60, 90, 120],
)

BALANCE = Gauge(
    "captcha_balance_usd",
    "Current CaptchaAI account balance in USD",
)

QUEUE_LENGTH = Gauge(
    "captcha_queue_length",
    "Number of pending CAPTCHA tasks",
)


class InstrumentedSolver:
    """Solver with Prometheus metric instrumentation."""

    def __init__(self, api_key):
        self.api_key = api_key
        self.base = "https://ocr.captchaai.com"

    def solve(self, method, **params):
        """Solve CAPTCHA with metric collection."""
        SOLVES_TOTAL.labels(method=method).inc()
        start = time.time()

        try:
            token = self._do_solve(method, params)
            duration = time.time() - start

            SOLVES_SUCCESS.labels(method=method).inc()
            SOLVE_DURATION.labels(method=method).observe(duration)

            return token

        except Exception as e:
            error_code = str(e)[:30]
            SOLVES_ERRORS.labels(
                method=method, error_code=error_code,
            ).inc()
            raise

    def update_balance(self):
        """Fetch and update balance metric."""
        resp = requests.get(f"{self.base}/res.php", params={
            "key": self.api_key,
            "action": "getbalance",
            "json": 1,
        }, timeout=15)
        balance = float(resp.json()["request"])
        BALANCE.set(balance)
        return balance

    def _do_solve(self, method, params, timeout=120):
        data = {"key": self.api_key, "method": method, "json": 1}
        data.update(params)

        resp = requests.post(
            f"{self.base}/in.php", data=data, timeout=30,
        )
        result = resp.json()

        if result.get("status") != 1:
            raise RuntimeError(result.get("request"))

        task_id = result["request"]
        start = time.time()

        while time.time() - start < timeout:
            time.sleep(5)
            resp = requests.get(f"{self.base}/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1,
            }, timeout=15)
            data = resp.json()
            if data["request"] != "CAPCHA_NOT_READY":
                if data.get("status") == 1:
                    return data["request"]
                raise RuntimeError(data["request"])

        raise TimeoutError("Solve timeout")


# Start metrics server on port 8000
start_http_server(8000)
print("Metrics server running on :8000/metrics")

method etiketi türleri ayrı süzmenizi sağlar. update_balance çağrısını her çözümde değil, ayrı bir zamanlayıcıda (örneğin 60 saniyede bir) çalıştırın; aksi halde gereksiz istek üretirsiniz. Sunucu ayağa kalktığında /metrics uç noktası tüm sayaç ve ölçerleri Prometheus'un kazıyabileceği düz metin biçiminde yayınlar.

Toplayıcı üç Prometheus aracını birlikte kullanır:

  • Counter — yalnızca artan sayaçlar (solves_total, solves_success, solves_errors).
  • Histogram — çözüm süresini önceden tanımlı bucket'lara dağıtır (solve_duration).
  • Gauge — anlık, iki yönde değişebilen değerler (balance, queue_length).

Prometheus'u yapılandırma

Çözücünüzü Prometheus'a hedef olarak tanıtın; 10 saniyelik kazıma aralığı gerçek zamanlı bir panel için yeterli.

# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:

  - job_name: "captcha-solver"
    static_configs:

      - targets: ["solver-app:8000"]
    scrape_interval: 10s

Birden fazla çözücünüz varsa her birini ayrı bir targets girdisi olarak ekleyin; Prometheus hepsini aynı iş altında toplar. Yapılandırırken iki noktaya dikkat edin:

  • scrape_interval değerini ortalama çözüm sürenizden kısa tutun, yoksa kısa dalgalanmaları kaçırırsınız.
  • Hedef adresi Compose servis adıyla verin (solver-app:8000), sabit IP ile değil.

Docker Compose ile yığını ayağa kaldırma

Çözücü, Prometheus ve Grafana'yı tek dosyada bağlayın.

# docker-compose.yml
version: "3.8"

services:
  solver:
    build: .
    environment:

      - CAPTCHAAI_KEY=${CAPTCHAAI_KEY}
    ports:

      - "8000:8000"

  prometheus:
    image: prom/prometheus:latest
    volumes:

      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:

      - "9090:9090"

  grafana:
    image: grafana/grafana:latest
    ports:

      - "3000:3000"
    environment:

      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:

      - grafana-data:/var/lib/grafana

volumes:
  grafana-data:

docker compose up -d komutundan sonra Prometheus 9090, Grafana ise 3000 portunda hazır olur. Grafana'ya ilk girişte veri kaynağı olarak http://prometheus:9090 adresini tanımlayın — servis adları Compose ağı içinde otomatik çözülür, ayrıca IP girmenize gerek yoktur.


Grafana panelleri ve PromQL sorguları

Dört panelle başlayın: başarı oranı, ortalama süre, hata dökümü ve bakiye. Sayaçlar yeniden başlatmada sıfırlandığı için oranları rate() ile hesaplayın.

Her panel farklı bir soruyu yanıtlar:

  • Başarı oranı — sistemin genel sağlık göstergesi.
  • Ortalama ve P95 süre — gecikme eğilimi ve en kötü durum.
  • Türe göre hata — sorunun kök nedeni.
  • Bakiye — yaklaşan kesinti riski.

Başarı oranı (PromQL)

rate(captcha_solves_success[5m])
/ rate(captcha_solves_total[5m]) * 100

Ortalama çözüm süresi

rate(captcha_solve_duration_seconds_sum[5m])
/ rate(captcha_solve_duration_seconds_count[5m])

Türe göre hata oranı

sum by (error_code) (
  rate(captcha_solves_errors[5m])
)

Zaman içinde bakiye

captcha_balance_usd

P95 çözüm süresi

histogram_quantile(0.95,
  rate(captcha_solve_duration_seconds_bucket[5m])
)

P95, kullanıcıların gerçekte deneyimlediği en kötü durumu ortalamadan daha dürüst yansıtır; SLA eşiklerinizi ortalama süreye değil P95'e göre belirleyin.


Uyarı kuralları

Panele sürekli bakmayın; eşikleri tanımlayın, sorun oluştuğunda uyarı gelsin.

# alert_rules.yml
groups:

  - name: captcha-alerts
    rules:

      - alert: LowBalance
        expr: captcha_balance_usd < 5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "CaptchaAI balance below $5"

      - alert: HighErrorRate
        expr: |
          rate(captcha_solves_errors[5m])
          / rate(captcha_solves_total[5m]) > 0.1
        for: 10m
        labels:
          severity: critical
        annotations:
          summary: "CAPTCHA error rate above 10%"

      - alert: SlowSolveTime
        expr: |
          histogram_quantile(0.95,
            rate(captcha_solve_duration_seconds_bucket[5m])
          ) > 60
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "P95 solve time exceeds 60s"

Uyarıları Alertmanager üzerinden Slack veya e-postaya yönlendirin. Örnekteki üç kural farklı sağlık boyutunu kapsar:

  • LowBalance — kesintiyi önlemek için finansal eşik.
  • HighErrorRate — 5 dakikalık pencerede hata oranı %10'u aşarsa kritik uyarı.
  • SlowSolveTime — P95 süre 60 saniyeyi geçerse performans uyarısı.

Her kuraldaki for süresi anlık dalgalanmaların yanlış alarm üretmesini engeller — hata oranı için 10 dakika, yavaş çözüm için 15 dakika makul başlangıç değerleridir.


Üretimde bakiye ve maliyeti izleme

CaptchaAI planları USD üzerinden ücretlendirilir — BASIC ($15/ay, 5 thread) en düşük kademedir — bu yüzden TL kurundaki dalgalanma aylık plan maliyetinizi değiştirmez. Ama bakiyeniz bittiğinde çözümler sessizce durur; captcha_balance_usd ölçerini ayrı bir Grafana paneline koyun ve düşük bakiye uyarısını tahmini değil gerçek saatlik harcama hızınıza göre ayarlayın. İstanbul saatiyle (Europe/Istanbul) gece yarısı gibi düşük trafikli pencerelerde bakiyeyi elle yüklüyorsanız, eşiği bir sonraki dolum zamanına kadar rahat yetecek biçimde seçin ki iş akışınız hafta sonu ortasında durmasın.


Ölçeklerken kuyruk derinliğini izleme

captcha_queue_length ölçeri, worker'larınızın gelen yükü karşılayıp karşılamadığını gösterir. Kuyruk sürekli büyüyorsa daha fazla thread veya worker devreye almanız gerekir. Panelde şu üç durumu ayırt edin:

  • Kuyruk uzunluğu düzenli artıyorsa kapasite yetersizdir.
  • P95 süre artarken kuyruk sabitse darboğaz çözüm tarafındadır.
  • İkisi de düşükse mevcut kurulum yükü rahat karşılıyordur.

Bu paneli başarı oranının hemen yanına koyun; kapasite darboğazını gerçek bir başarı düşüşünden en hızlı böyle ayırt edersiniz.


Sorun giderme

Sorun Sebep Düzeltme
/metrics'de ölçüm yok Sunucu başlatılmadı start_http_server(8000)'i çağırın
Prometheus "down" gösteriyor Yanlış hedef adres Docker ağını ve portu kontrol edin
Grafana veri göstermiyor Prometheus kaynak olarak eklenmedi Grafana'ya Prometheus veri kaynağı ekleyin
Yeniden başlatmada ölçümler sıfırlanıyor Sayaç sıfırlanması beklenen davranış Ham sayaç yerine rate() kullanın

Sık sorulan sorular

Çözüm oranı metriği ne sıklıkta güncellenir?

Kazıma aralığı kadar sık — örnekte her 10 saniyede bir, yani panel neredeyse gerçek zamanlı. prometheus_client işlem başına 1 ms'nin altında yük ekler; sık kazımanın anlamlı maliyeti yoktur.

Başarı oranı düştüğünde önce neye bakmalıyım?

Türe göre hata oranı paneline. error_code etiketi, sorunun tek bir türde mi yoksa tüm isteklerde mi olduğunu hemen gösterir. Ardından P95 süresine bakın.

Düşük bakiye uyarısını hangi eşiğe ayarlamalıyım?

Ortalama saatlik harcamanızın iki-üç katına. Örnekteki < 5 USD küçük iş yükleri için makuldür; yoğun boru hatlarında eşiği yükseltin.

Aynı kurulumu birden fazla worker ile kullanabilir miyim?

Evet. Her worker kendi /metrics uç noktasını yayınlar; Prometheus tüm hedefleri kazır ve Grafana örnekler arası otomatik toplar.

Histogram bucket'larını nasıl seçmeliyim?

Beklenen çözüm süresi aralığınızı kapsayacak biçimde. Örnekteki 5, 10, 15, 20, 30, 45, 60, 90, 120 saniyelik değerler çoğu tür için iyi bir başlangıçtır; çözümleriniz sürekli tek bir bucket'ta toplanıyorsa aralığı daraltın ki P95 anlamlı kalsın.


Üretime almadan önce kısa kontrol listesi

Kurulumu canlıya taşımadan önce şunları doğrulayın:

  • /metrics uç noktası çözücü konteynerinde erişilebilir.
  • Prometheus hedefi up durumda ve son kazıma güncel.
  • Grafana'da başarı oranı, süre, hata ve bakiye panelleri veri gösteriyor.
  • Üç uyarı kuralı da yüklendi ve bildirim kanalı test edildi.
  • Düşük bakiye eşiği gerçek harcama hızınıza göre ayarlandı.

İlgili rehberler


Çözüm oranınızı bugün Prometheus'la izlemeye başlayın — CaptchaAI panelinizi bağlayın.

Bu makale için yorumlar devre dışı bırakılmıştır.