SerpBase 预算感知调度:让采集任务不再「跑一半没额度」

采集中途没额度,是最贵的一种失败:任务跑了一半,数据缺一块,重跑又要从头开始,告警在半夜响。后来我给管道加了「预算感知调度」——任务前查余额、按类型预留额度、余额不足时降级执行。这篇讲这三层的设计。

第一层:准入——不启动,比跑一半便宜

任务启动前,先估算本次需要多少 credits,和余额比:

# catalog.yaml —— 端点目录价(从官方文档同步)
PRICE = {"google/search": 1, "google/news/search": 1, "google/maps/search": 2, "google/maps/detail": 3}

def estimate_cost(tasks: list[dict]) -> int:
    """按目录价估算任务成本(上限,不是实际扣费)"""
    return sum(PRICE[t["endpoint"]] for t in tasks)

def preflight(tasks: list[dict]) -> bool:
    cost = estimate_cost(tasks)
    balance = account_credits()["credits"]
    if balance < cost:
        alert(f"余额不足:需要 {cost},剩余 {balance},任务未启动")
        return False
    return True

预估按目录价算,不按实际扣费算——未确认的计费是 unknown,按上限估才安全。余额不够就不启动:任务没跑,数据是「没有」;任务跑一半,数据是「缺一块」,后者更难查。

第二层:预留——并发任务别互相抢

多个任务并发时,各查各的余额会同时通过准入、同时烧光。加一层预留:

import threading

class Budget:
    def __init__(self):
        self.lock = threading.Lock()
        self.reserved = 0

    def reserve(self, cost: int) -> bool:
        with self.lock:
            balance = account_credits()["credits"]
            if balance - self.reserved >= cost:
                self.reserved += cost
                return True
            return False

    def settle(self, cost: int):
        with self.lock:
            self.reserved -= cost

任务开始前 reserve,结束后 settle。并发任务的准入判断基于「余额 - 已预留」,互不打架。

第三层:降级——余额低时砍什么

余额不足以跑全部时,按优先级砍,而不是整体失败:

优先级 内容 余额不足时
P0 核心关键词日报 保留
P1 竞品监控 保留,降频
P2 非核心端点(图片、地图详情) 跳过
P3 探索性查询 跳过
def plan(tasks: list[dict], balance: int) -> list[dict]:
    """按预算裁剪任务,返回可执行部分"""
    ordered = sorted(tasks, key=lambda t: t["priority"])
    remaining, plan = balance, []
    for t in ordered:
        cost = PRICE[t["endpoint"]]
        if cost <= remaining:
            plan.append(t)
            remaining -= cost
    if skipped := len(tasks) - len(plan):
        log.warning("预算不足,跳过 %d 个任务", skipped)
    return plan

降级必须显式记录:跳过了什么、为什么。事后复盘时,「那天为什么少了一批数据」要有答案。

和限流的分工

这两层经常被混为一谈,其实管的东西不同:

  • credits 限流管「速率」:每秒烧多少,防止触发 429(并发篇的内容)
  • 预算管理管「总量」:这个月/今天总共能烧多少,防止中途断粮

一个管节奏,一个管总量,两层都要。

踩坑记录

坑 1:只看总余额。 限时额度到期后余额会跳水——permanent_credits 和 expiring_credits 要分开看,准入判断用能长期持有的那部分。

坑 2:预估按实际扣费算。 计费未确认时 credits_charged 是 null,按它预估会把预算估漏。按目录价上限估。

坑 3:并发不预留。 三个任务同时通过准入,把余额在一次并发里烧光。预留机制补上。

坑 4:降级不记录。 静默跳过的任务,事后没人知道数据为什么缺。跳过要进日志。

坑 5:告警阈值不留余量。 余额等于「预估成本」才告警,等告警响的时候已经来不及买额度了。阈值要留出采购和响应时间。

小结

预算感知调度把「额度管理」从「月底看账单」前移到「每次任务前」:准入防跑一半、预留防并发抢、降级防整体失败。三层都不复杂,但堵住的是采集中最贵的那类事故——不是没数据,是缺一半还不知道为什么。

余额查询端点(GET /account/credits)和计费字段说明见 SerpBase 官方文档。你们怎么管采集预算?评论区聊聊。

posted @ 2026-10-17 10:38  蜘蛛人  阅读(6)  评论(0)    收藏  举报