SerpBase 多品类采集:并发要按 credits 限流
以前管道里全是 1-credit 的搜索端点,「控并发」基本等于「控 QPS」,一个令牌桶就完事。后来 catalog 扩到 39 个端点、6 个大类,价格从 1 到 3 credits 不等——地图详情一次 3 credits,是搜索的三倍。这时冒出一个问题:并发数控制得住请求数,控制不住成本。
问题:请求级限流的盲区
原来的令牌桶按「请求数」计量:每秒放 5 个请求,跑满就是 5 个。混合品类之后,同样 5 个并发:
- 5 个搜索(1 credit)= 5 credits/秒
- 5 个地图详情(3 credits)= 15 credits/秒
成本差三倍,限流器却毫无察觉。请求数是表象,credits 才是成本。
方案:令牌桶改成按 credits 计量
import threading, time
class CreditLimiter:
"""按 credits 计量的令牌桶"""
def __init__(self, credits_per_sec: float, burst: int = 10):
self.rate = credits_per_sec
self.burst = burst
self.tokens = float(burst)
self.updated = time.monotonic()
self.lock = threading.Lock()
def acquire(self, cost: int) -> None:
while True:
with self.lock:
now = time.monotonic()
self.tokens = min(self.burst, self.tokens + (now - self.updated) * self.rate)
self.updated = now
if self.tokens >= cost:
self.tokens -= cost
return
wait = (cost - self.tokens) / self.rate
time.sleep(wait)
用法:请求之前先按「这个端点的价格」准入。
def fetch(endpoint: str, payload: dict) -> dict:
limiter.acquire(PRICE_TABLE[endpoint]) # 按成本准入,不按请求数
resp = session.post(f"{BASE}/{endpoint}", json=payload, timeout=(5, 30))
return resp.json()
目录价表:价格是配置,不是常量
# catalog.yaml —— 端点一多,硬编码必过期
google/search: 1
google/image/search: 1
google/news/search: 1
google/maps/search: 2
google/maps/detail: 3
amazon/product: 2
web/scrape: 1
这份表从官方文档拉取、随文档更新。价格调整时改配置,不动代码——这是多端点管道能长期维护的前提。
和退避、429 的配合
credits 限流管「匀速消耗」,429 处理管「上游拒绝」,两层各司其职:
- 收到 429:把
credits_per_sec降半——注意降的是速率,不是并发数 - 恢复后加性升回(每次 +10%),别一步拉满
- 指数退避的重试请求同样走 limiter——重试也是真实成本
观测:按端点记账
响应里的 credits_charged 是实际扣费,落库后按端点聚合:
SELECT endpoint, SUM(credits_charged) AS credits, COUNT(*) AS calls
FROM request_log
GROUP BY endpoint ORDER BY credits DESC;
这张表回答一个常见问题:「预算到底被哪个端点吃掉了?」多品类管道里,答案经常出人意料——你可能以为搜索是大头,其实地图详情和电商查询悄悄占了一半。
另外注意:credits_charged 可能为 null(计费未确认),对账要按窗口做,把未知项当风险敞口,别强行按 0 记账。
踩坑记录
坑 1:按请求数限流。 混合品类后成本失控,限流器却显示「一切正常」——它只看请求数,不看价格。
坑 2:价格硬编码。 39 个端点写死在代码里,文档一改全线失真。
坑 3:burst 设太大。 令牌桶允许瞬时突发,一个 burst 50 打 3-credit 端点就是 150 credits 瞬间蒸发。burst 要按「最贵端点 × 覆盖秒数」来设。
坑 4:429 只降并发。 并发减半,但每个请求还是 3 credits,成本速率没降多少。要降的是 credits 速率。
坑 5:null 当 0 记账。 未确认计费强行按 0 处理,月底对账永远差一笔。
小结
多品类采集把「并发控制」从一维变成二维:请求数决定节奏,credits 决定成本。令牌桶按 credits 计量、目录价按配置维护、429 降速率——这套组合拳,是在 39 个端点、1 到 3 credits 的 catalog 下把管道开稳的前提。
端点目录价与计费字段(含 null 语义)见 SerpBase 官方文档。你们的多端点管道怎么控成本?评论区聊聊。

浙公网安备 33010602011771号