DevOps & Scaling

Triển khai Blue-Green cho cơ sở hạ tầng giải CAPTCHA

Nâng cấp quy trình giải CAPTCHA của bạn không có nghĩa là ngừng hoạt động. Triển khai xanh lam cho phép bạn chạy hai môi trường giống hệt nhau — chuyển lưu lượng truy cập sang phiên bản mới, xác minh rằng nó hoạt động và quay lại ngay lập tức nếu có sự cố.

Kiến trúc xanh lam

                    ┌─────────────────────┐
[Scraper Clients] → │   Traffic Router    │
                    └──────┬──────┬───────┘
                           │      │
                     Active│      │Standby
                           ▼      ▼
                    ┌───────┐  ┌───────┐
                    │ BLUE  │  │ GREEN │
                    │Workers│  │Workers│
                    └───┬───┘  └───┬───┘
                        │          │
                        └────┬─────┘
                             ▼
                    [CaptchaAI API]

Thực hiện

Python – Bộ định tuyến xanh lam

import os
import time
import threading
import requests

API_KEY = os.environ["CAPTCHAAI_API_KEY"]

class CaptchaWorkerPool:
    """Represents one environment (blue or green)."""

    def __init__(self, name, config):
        self.name = name
        self.config = config
        self.session = requests.Session()
        self.tasks_solved = 0
        self.errors = 0
        self.healthy = True

    def solve(self, task):
        resp = self.session.post("https://ocr.captchaai.com/in.php", data={
            "key": API_KEY,
            "method": task.get("method", "userrecaptcha"),
            "googlekey": task["sitekey"],
            "pageurl": task["pageurl"],
            "json": 1
        })
        data = resp.json()
        if data.get("status") != 1:
            self.errors += 1
            return {"error": data.get("request")}

        captcha_id = data["request"]
        for _ in range(60):
            time.sleep(5)
            result = self.session.get(
                "https://ocr.captchaai.com/res.php",
                params={
                    "key": API_KEY,
                    "action": "get",
                    "id": captcha_id,
                    "json": 1
                }
            ).json()
            if result.get("status") == 1:
                self.tasks_solved += 1
                return {"solution": result["request"]}
            if result.get("request") != "CAPCHA_NOT_READY":
                self.errors += 1
                return {"error": result.get("request")}

        self.errors += 1
        return {"error": "TIMEOUT"}

    @property
    def error_rate(self):
        total = self.tasks_solved + self.errors
        return self.errors / total if total > 0 else 0.0

    @property
    def stats(self):
        return {
            "name": self.name,
            "solved": self.tasks_solved,
            "errors": self.errors,
            "error_rate": round(self.error_rate, 4),
            "healthy": self.healthy
        }

class BlueGreenRouter:
    def __init__(self, blue_config, green_config):
        self.blue = CaptchaWorkerPool("blue", blue_config)
        self.green = CaptchaWorkerPool("green", green_config)
        self.active = self.blue
        self.standby = self.green
        self.lock = threading.Lock()

    def solve(self, task):
        """Route task to the active environment."""
        with self.lock:
            pool = self.active
        return pool.solve(task)

    def switch(self):
        """Swap active and standby environments."""
        with self.lock:
            self.active, self.standby = self.standby, self.active
            print(f"Switched: {self.active.name} is now ACTIVE")
        return self.active.name

    def rollback(self):
        """Switch back to the previous environment."""
        return self.switch()

    def canary_test(self, test_tasks, threshold=0.9):
        """Run test tasks on standby before switching."""
        successes = 0
        for task in test_tasks:
            result = self.standby.solve(task)
            if "solution" in result:
                successes += 1

        success_rate = successes / len(test_tasks) if test_tasks else 0
        passed = success_rate >= threshold
        print(
            f"Canary test: {successes}/{len(test_tasks)} "
            f"({success_rate:.0%}) — {'PASS' if passed else 'FAIL'}"
        )
        return passed

    @property
    def status(self):
        return {
            "active": self.active.stats,
            "standby": self.standby.stats
        }

# Usage
router = BlueGreenRouter(
    blue_config={"version": "1.2.0", "workers": 4},
    green_config={"version": "1.3.0", "workers": 4}
)

# Canary test before switching
test_tasks = [
    {"sitekey": "6Le-wvkS...", "pageurl": "https://example.com/test"}
]

if router.canary_test(test_tasks, threshold=0.8):
    router.switch()
    print(f"Now active: {router.status['active']['name']}")
else:
    print("Canary failed — staying on current environment")

JavaScript – Trình chuyển đổi xanh lam-xanh tự động

const axios = require("axios");

const API_KEY = process.env.CAPTCHAAI_API_KEY;

class BlueGreenDeployment {
  constructor() {
    this.environments = {
      blue: { name: "blue", version: null, solved: 0, errors: 0 },
      green: { name: "green", version: null, solved: 0, errors: 0 },
    };
    this.activeEnv = "blue";
  }

  get active() {
    return this.environments[this.activeEnv];
  }
  get standby() {
    return this.environments[this.activeEnv === "blue" ? "green" : "blue"];
  }

  async deploy(version, config = {}) {
    const target = this.standby;
    target.version = version;
    target.solved = 0;
    target.errors = 0;

    console.log(`Deployed v${version} to ${target.name} (standby)`);

    // Run canary checks
    const canaryPassed = await this.canaryCheck(config.canaryTasks || []);
    if (!canaryPassed && config.canaryTasks?.length > 0) {
      console.log("Canary check failed — aborting deployment");
      return { success: false, reason: "canary_failed" };
    }

    // Switch traffic
    this.activeEnv = target.name;
    console.log(`Switched traffic to ${target.name} (v${version})`);

    // Monitor for rollback
    if (config.monitorDuration) {
      const stable = await this.monitorAfterSwitch(config.monitorDuration);
      if (!stable) {
        this.rollback();
        return { success: false, reason: "post_deploy_errors" };
      }
    }

    return { success: true, active: this.activeEnv };
  }

  async canaryCheck(tasks) {
    if (tasks.length === 0) return true;

    let successes = 0;
    for (const task of tasks) {
      try {
        await this.solveCaptcha(task);
        successes++;
      } catch (err) {
        console.log(`Canary task failed: ${err.message}`);
      }
    }

    const rate = successes / tasks.length;
    console.log(`Canary: ${successes}/${tasks.length} (${(rate * 100).toFixed(0)}%)`);
    return rate >= 0.8;
  }

  async monitorAfterSwitch(durationMs) {
    const start = Date.now();
    const checkInterval = 10000;

    while (Date.now() - start < durationMs) {
      await new Promise((r) => setTimeout(r, checkInterval));
      const errorRate = this.active.errors /
        Math.max(1, this.active.solved + this.active.errors);

      if (errorRate > 0.2) {
        console.log(`Error rate ${(errorRate * 100).toFixed(1)}% — triggering rollback`);
        return false;
      }
    }
    return true;
  }

  rollback() {
    const previous = this.activeEnv === "blue" ? "green" : "blue";
    console.log(`Rolling back: ${this.activeEnv} → ${previous}`);
    this.activeEnv = previous === "blue" ? "blue" : "green";
  }

  async solveCaptcha(task) {
    const submitResp = await axios.post("https://ocr.captchaai.com/in.php", null, {
      params: {
        key: API_KEY,
        method: "userrecaptcha",
        googlekey: task.sitekey,
        pageurl: task.pageurl,
        json: 1,
      },
    });

    if (submitResp.data.status !== 1) {
      this.active.errors++;
      throw new 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) {
        this.active.solved++;
        return pollResp.data.request;
      }
      if (pollResp.data.request !== "CAPCHA_NOT_READY") {
        this.active.errors++;
        throw new Error(pollResp.data.request);
      }
    }
    this.active.errors++;
    throw new Error("TIMEOUT");
  }
}

// Deploy new version with canary and monitoring
const deployer = new BlueGreenDeployment();

deployer
  .deploy("1.3.0", {
    canaryTasks: [
      { sitekey: "6Le-wvkS...", pageurl: "https://example.com/test" },
    ],
    monitorDuration: 60000, // Monitor for 1 minute after switch
  })
  .then((result) => console.log("Deploy result:", result));

Quy trình triển khai

Bước hành động Kích hoạt khôi phục
1 Triển khai mã mới vào chế độ chờ Xây dựng thất bại
2 Chạy thử nghiệm canary ở chế độ chờ Tỷ lệ thành công < 80%
3 Chuyển lưu lượng truy cập sang phiên bản mới
4 Giám sát tỷ lệ lỗi (5 phút) Tỷ lệ lỗi > 20%
5 Ngừng hoạt động môi trường cũ

Sổ tay cắt giảm giao thông

  • Giữ các nhóm màu xanh lam và xanh lục trên các đầu dò tình trạng được phản chiếu trước khi gửi bất kỳ lưu lượng truy cập trực tiếp nào đến ngăn xếp mới.
  • Thay đổi lưu lượng truy cập theo các giai đoạn rõ ràng và yêu cầu độ trễ ổn định cùng với việc kiểm tra tỷ lệ từ chối trước mỗi bước.
  • Khôi phục ngay lập tức nếu giải quyết được độ trễ, tỷ lệ từ chối mục tiêu hoặc độ sâu hàng đợi vượt quá ngưỡng đã thỏa thuận.

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
Canary vượt qua nhưng sản xuất thất bại Nhiệm vụ kiểm tra quá đơn giản Sử dụng các nhiệm vụ thực tế từ hàng đợi sản xuất
Quay lại thường xuyên Ngưỡng giám sát tích cực Tăng ngưỡng lỗi; thời gian ngâm lâu hơn
Phân chia lưu lượng không rõ ràng trong quá trình chuyển đổi Yêu cầu trong chuyến bay trên môi trường cũ Chờ cho các nhiệm vụ trên chuyến bay hoàn tất trước khi ngừng hoạt động
Cả hai môi trường đều trở nên không lành mạnh Lỗi phụ thuộc được chia sẻ (mạng, API) Bộ ngắt mạch; không quay trở lại vì các vấn đề về cơ sở hạ tầng

Câu hỏi thường gặp

Thử nghiệm canary nên chạy trong bao lâu?

Chạy ít nhất 10 giải CAPTCHA thực trên môi trường chờ. Đối với các hệ thống quan trọng, hãy chạy phần trăm lưu lượng sản xuất (5–10%) qua chế độ chờ trong 10 phút trước khi chuyển đổi hoàn toàn.

Tôi có thể thực hiện màu xanh lam với một máy chủ không?

Có - chạy màu xanh lam và xanh lục dưới dạng các quy trình hoặc vùng chứa riêng biệt trên cùng một máy chủ. Sử dụng proxy ngược (NGINX) để chuyển đổi lưu lượng giữa các cổng.

Sự khác biệt giữa triển khai xanh dương và xanh hoàng yến là gì?

Màu xanh lam chuyển 100% lưu lượng truy cập cùng một lúc. Canary tăng dần lưu lượng truy cập sang phiên bản mới (1% -> 10% -> 50% -> 100%). Màu xanh lam đơn giản hơn; canary an toàn hơn cho các hệ thống quy mô lớn.

Các bước tiếp theo

Triển khai với sự tự tin —lấy khóa API CaptchaAI của bạnvà thiết lập triển khai không có thời gian ngừng hoạt động.

Hướng dẫn liên quan:

Os comentários estão desativados para este artigo.

Postagens relacionadas

DevOps & Scaling Xây dựng giải quyết CAPTCHA theo sự kiện bằng AWS SNS và CaptchaAI
Hướng dẫn Dev Ops xây dựng giải pháp giải quyết tình huống CAPTCHA bằng AWS SNS và Captcha AI, với các quyết định về kiến ​​trúc, các cân nhắc vận hành và mô hì...

Hướng dẫn Dev Ops xây dựng giải pháp giải quyết tình huống CAPTCHA bằng AWS SNS và Captcha AI, với các quyết đ...

Apr 25, 2026
DevOps & Scaling Công nhân giải quyết CAPTCHA tự động mở rộng quy mô
Hướng dẫn Dev Ops về Công nhân giải quyết quy trình tự động mở rộng CAPTCHA, với các quyết định về kiến ​​trúc, các cân nhắc vận hành và mô hình tự động hóa cho...

Hướng dẫn Dev Ops về Công nhân giải quyết quy trình tự động mở rộng CAPTCHA, với các quyết định về kiến ​​trúc...

Apr 24, 2026
Tutorials Xây dựng hàng đợi giải CAPTCHA bằng Python với CaptchaAI
Hướng dẫn từng bước để Xây dựng hàng đợi giải mã CAPTCHA bằng Python với Captcha AI, với các ví dụ có thể sử dụng lại trực tiếp và quy trình làm việc Captcha AI...

Hướng dẫn từng bước để Xây dựng hàng đợi giải mã CAPTCHA bằng Python với Captcha AI, với các ví dụ có thể sử d...

May 01, 2026