DevOps и масштабирование

Мониторинг скорости решения CAPTCHA с помощью Prometheus и Grafana

Для решения производственной CAPTCHA необходима наблюдаемость. Prometheus собирает метрики, Grafana визуализирует их, а оповещения выявляют проблемы до того, как они повлияют на ваш конвейер.


Метрики для отслеживания

Метрика Тип Цель
captcha_solves_total Прилавок Всего попыток решения
captcha_solves_success Прилавок Успешные решения
captcha_solves_errors Прилавок Неудачные решения (по типу ошибки)
captcha_solve_duration Гистограмма Решите распределение времени
captcha_balance Измерять Остаток текущего счета
captcha_queue_length Измерять Ожидающие задачи в очереди

Экспортер метрик Python

# 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")

Конфигурация Прометея

# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:

  - job_name: "captcha-solver"
    static_configs:

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

Docker Compose Stack

# 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:

Запросы на панель управления Grafana

Уровень успеха (PromQL)

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

Среднее время решения

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

Коэффициент ошибок по типу

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

Баланс с течением времени

captcha_balance_usd

P95 Продолжительность решения

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

Правила оповещения

# 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"

Поиск неисправностей

Проблема Причина Исправить
На /metrics нет показателей Сервер не запущен Позвоните start_http_server(8000)
Прометей показывает «вниз» Неправильный целевой адрес Проверьте сеть и порт Docker
Графана не показывает данных Прометей не добавлен в качестве источника Добавьте источник данных Prometheus в Grafana
Метрики сбрасываются при перезапуске Ожидается сброс счетчика Используйте rate(), а не необработанные счетчики.

Часто задаваемые вопросы

Сколько накладных расходов добавляет Прометей?

Незначительный. Библиотека prometheus_client добавляет <1 мс на каждую метрическую операцию. Соскребание каждые 10-15 секунд не имеет значимого эффекта.

Могу ли я использовать это с несколькими экземплярами рабочих?

Да. Каждый рабочий процесс предоставляет свою собственную конечную точку /metrics. Прометей очищает все цели. Запросы Grafana автоматически агрегируются по всем экземплярам.

С какой панели мне начать?

Начните с четырех панелей: уровень успеха, среднее время решения, разбивка ошибок и баланс. Добавляйте глубину очереди и пропускную способность по мере масштабирования.


Связанные руководства

  • Создание информационной панели использования
  • Рабочие инструменты автоматического масштабирования

Полная наблюдаемость —монитор CaptchaAIс Прометеем сегодня.

Комментарии для этой статьи отключены.