2. 限流基础概念

在催收与 Model Serving 场景中,限流(Rate Limiting)是保障系统稳定性的第一道防线。本章从定义、目的与核心算法三个维度建立限流知识体系,为后续的熔断与模型服务限流策略打下基础。

2.1 限流定义

限流是一种通过控制单位时间内允许通过的请求数量、并发数或数据量,来防止系统过载的流量管控手段。在催收系统中,限流作用于以下三个关键层面:

  • API 网关层:限制外部催收机构、催收员客户端的请求速率。
  • 业务服务层:控制案件分配、策略计算、外呼触发的并发量。
  • 模型推理层:限制模型 Serving 的 QPS(每秒查询数)与批处理大小。
催收场景提示: 催收系统在月初、月末或节假日前后常出现流量尖峰。限流不是拒绝所有超量请求,而是让系统在可控负载下优先处理高优先级案件(如逾期 30+ 天、大额欠款)。

2.2 限流目的

限流的核心目标可归纳为两大维度:

目的维度 具体说明 催收场景示例
保护系统 防止突发流量击穿数据库、缓存、模型推理服务等后端资源,避免级联故障。 催收员批量导入案件时,限制导入接口的 TPS,防止数据库连接池耗尽。
公平使用 确保多个租户、多个催收机构或模型版本之间公平分配服务资源,防止单一来源抢占全部容量。 两家催收机构同时调用评分模型,限流保证每家最多占用 50% 的模型推理容量。
成本控制 在云原生架构中,限流直接关联计算资源(GPU/CPU)的预算管控。 模型 Serving 按 QPS 计费,限流防止因流量突增导致月度推理成本超支。

2.3 限流常见算法

业界主流限流算法包括令牌桶、漏桶与计数器三种。以下从原理、适用场景与催收适配性三个维度进行对比。

2.3.1 令牌桶算法(Token Bucket)

令牌桶以固定速率向桶中添加令牌,每个请求需消耗一个令牌才能被处理。桶容量限制最大突发流量。

  • 核心参数:令牌填充速率(r)、桶容量(b)。
  • 优势:允许一定程度的突发流量,适合模型推理等需要容忍短时峰值的场景。
  • 劣势:突发流量可能超过后端实际处理能力,需配合熔断使用。
  • 催收适用:催收员批量查询案件详情时,允许短时突发查询,但长期平均速率受控。

2.3.2 漏桶算法(Leaky Bucket)

漏桶将请求放入队列,以恒定速率从队列中取出处理。桶满时新请求被直接丢弃。

  • 核心参数:漏出速率(r)、桶容量(b)。
  • 优势:输出流量绝对平滑,适合保护数据库等对写入速率敏感的后端。
  • 劣势:无法应对突发流量,可能导致请求排队超时。
  • 催收适用:催收外呼记录写入数据库时,使用漏桶保证写入速率不超过数据库 IOPS 上限。

2.3.3 计数器算法(Counter / Fixed Window)

计数器在固定时间窗口(如 1 秒)内累计请求数,超过阈值则拒绝后续请求。窗口结束后计数器重置。

  • 核心参数:时间窗口大小(w)、窗口内最大请求数(n)。
  • 优势:实现简单,内存占用极低。
  • 劣势:存在窗口边界流量突刺问题(临界效应),精度较低。
  • 催收适用:非核心监控接口(如健康检查)的简易限流,对精度要求不高的场景。
算法选型建议: 在催收 Model Serving 场景中,推荐令牌桶作为默认算法——它既能容忍催收员操作带来的短时突发,又能通过桶容量限制最大并发推理请求,避免 GPU 显存溢出。漏桶更适合下游存储层限流,计数器仅用于低精度监控接口。

2.4 三种算法对比总览

对比维度 令牌桶 漏桶 计数器
突发处理能力 允许突发(受桶容量限制) 不允许突发 窗口内允许突发
输出流量形态 平均速率可控,可突发 绝对平滑 阶梯状,窗口边界不平滑
实现复杂度 中等 中等 低
内存开销 低(仅维护桶状态) 低(需维护队列) 极低(仅计数器)
催收 Model Serving 推荐度 ★★★★★ ★★★☆☆ ★★☆☆☆

2.5 限流算法工作流程对比(SVG)

下图展示三种限流算法在催收请求处理中的核心流程差异:

三种限流算法工作流程对比 令牌桶算法 令牌生成器 固定速率 r 添加令牌 令牌桶 容量 b,存储未使用令牌 请求处理 消耗 1 个令牌则通过 令牌不足 → 拒绝/排队 漏桶算法 请求入队 放入队列尾部 漏桶队列 容量 b,FIFO 排队 恒定漏出 固定速率 r 处理请求 队列满 → 直接丢弃 计数器算法 时间窗口 固定长度 w(如 1s) 计数器 累计请求数 n 阈值判断 n < 阈值 → 通过 n ≥ 阈值 → 拒绝 催收场景选型建议 令牌桶:模型推理服务(允许突发,控制平均速率) 漏桶:数据库写入、外呼记录落库(要求绝对平滑) 计数器:健康检查、非核心监控接口(实现简单,精度要求低)

2.6 限流在催收 Model Serving 中的落地要点

将限流算法应用于催收模型推理服务时,需关注以下工程要点:

  • 令牌桶容量与模型批处理大小对齐:桶容量 b 应 ≥ 模型最大批处理大小,避免因限流导致批处理无法填满,降低 GPU 利用率。
  • 限流与超时联动:被限流的请求不应无限等待,需设置合理的排队超时时间(如 500ms),超时后返回 429 Too Many Requests。
  • 多级限流策略:在网关层(全局 QPS 限流)与服务层(每个模型版本独立限流)同时部署,形成双层保护。
  • 动态限流配置:催收业务流量具有明显的日周期特征,建议支持按时间段调整限流阈值(如白天催收高峰期提高模型推理限流上限)。
常见陷阱: 仅依赖单层限流。例如只在网关层限流但未对模型 Serving 实例做限流,当网关限流配置错误或绕过网关的直连请求涌入时,模型服务仍可能被击穿。正确的做法是网关层 + 服务层双重限流。

2.7 限流配置示例(令牌桶 + 漏桶组合)

以下是一个催收系统中针对模型推理服务(令牌桶)与数据库写入(漏桶)的限流配置伪代码:

# 模型推理服务限流 —— 令牌桶
rate_limiter_model = TokenBucket(
    rate=100,       # 每秒填充 100 个令牌
    capacity=200,   # 桶容量 200,允许短时突发
    timeout_ms=500  # 等待令牌超时 500ms
)

# 催收外呼记录写入限流 —— 漏桶
rate_limiter_db = LeakyBucket(
    leak_rate=50,   # 每秒处理 50 条记录
    capacity=100,   # 队列容量 100
    drop_policy="tail_drop"  # 队列满时丢弃最早请求
)

# 请求处理流程
def handle_collection_request(request):
    # 1. 模型推理前获取令牌
    if not rate_limiter_model.try_acquire():
        return HTTPStatus.TOO_MANY_REQUESTS, "模型推理限流,请稍后重试"

    # 2. 执行模型推理
    score = model.predict(request.features)

    # 3. 写入外呼记录前检查漏桶
    if not rate_limiter_db.try_acquire():
        # 记录降级:写入本地日志,异步补偿
        log_to_local_file(request, score)
        return HTTPStatus.OK, {"score": score, "write_status": "deferred"}

    # 4. 正常写入数据库
    db.insert(collection_record(request, score))
    return HTTPStatus.OK, {"score": score, "write_status": "written"}
生产环境建议: 上述代码中的限流器应使用 Redis 或本地原子计数器实现分布式一致性。在 Kubernetes 部署的 Model Serving 中,推荐使用 Envoy 的全局速率限制过滤器 或 Istio 的 RateLimiter 作为网关层限流,服务层使用 Guava RateLimiter(Java)或 aioredis-rate-limiter(Python)实现实例级限流。