2. 限流基础概念

在催收触达API场景中,限流(Rate Limiting)是保护系统不被突发流量冲垮的第一道防线。本章从定义、目标和核心算法三个维度建立限流知识体系,为后续的熔断与降级实操打下理论基础。

2.1 限流定义

限流是一种通过控制单位时间内允许通过的请求数量,来保护系统资源不被过度消耗的技术手段。在催收触达API中,限流通常作用于以下维度:

  • 用户维度:单个催收员或催收系统账号的请求频率
  • 接口维度:特定催收触达接口(如短信、语音、邮件)的调用次数
  • IP维度:来源IP的请求速率,防止恶意爬取或攻击
  • 全局维度:整个API网关的总吞吐量上限
实操提示:催收触达API的限流阈值通常需要结合运营商通道能力、数据库连接池大小、下游系统处理能力综合设定。建议初始阈值设为通道容量的70%,预留30%的缓冲水位。

2.2 限流目标

限流并非简单的“拒绝请求”,而是有明确的业务和技术目标:

目标 说明 催收场景示例
保护系统 防止突发流量耗尽CPU、内存、数据库连接等资源 避免大量催收请求同时涌入导致短信通道阻塞
公平使用 确保所有调用方都能获得合理的服务配额 防止某个催收员占用全部通道资源,导致其他催收员无法触达
成本控制 避免因超量调用产生额外费用 短信、语音通道通常按量计费,限流可控制预算
服务质量 维持API响应时间的稳定性 限流后请求排队等待,避免大量请求超时或失败

2.3 常见限流算法

不同的限流算法在精度、内存占用、突发处理能力上各有优劣。以下是催收触达API中最常用的三种算法:

2.3.1 计数器算法

计数器算法是最简单的实现方式:在固定时间窗口内维护一个计数器,请求到达时计数器加1,超过阈值则拒绝。窗口结束后计数器重置。

// 计数器算法伪代码
long currentTime = System.currentTimeMillis();
if (currentTime - windowStart > windowSize) {
    // 新窗口开始
    counter = 0;
    windowStart = currentTime;
}
if (counter >= threshold) {
    reject(); // 拒绝请求
} else {
    counter++;
    process(); // 处理请求
}
边界问题:计数器算法存在“窗口临界突变”问题。例如窗口大小为1秒、阈值为100,如果在第0.9秒和第1.1秒各涌入100个请求,实际在0.2秒内通过了200个请求,导致瞬时流量峰值超过阈值。催收场景中,这种突发可能导致通道瞬间过载。

2.3.2 漏桶算法

漏桶算法将请求视为水滴,以固定速率从桶底漏出处理。桶的容量有限,当桶满时新请求被丢弃。该算法强制输出速率恒定,适合需要平滑流量的场景。

// 漏桶算法伪代码
long now = System.currentTimeMillis();
long elapsed = now - lastLeakTime;
// 计算这段时间漏出的水量
long leaked = elapsed * leakRate;
water = Math.max(0, water - leaked);
if (water < bucketCapacity) {
    water++; // 请求入桶
    process(); // 处理请求(实际由漏出速率控制)
} else {
    reject(); // 桶满,拒绝请求
}
lastLeakTime = now;
适用场景:漏桶算法非常适合催收触达API中的短信、语音通道调用。这些通道通常有固定的每秒发送上限(如500条/秒),漏桶可以严格保证输出速率不超过通道能力,避免被运营商限频或封禁。

2.3.3 令牌桶算法

令牌桶算法以固定速率向桶中添加令牌,请求到达时需获取令牌才能处理。桶中可累积一定数量的令牌,允许一定程度的突发流量。这是业界最常用的限流算法之一。

// 令牌桶算法伪代码
long now = System.currentTimeMillis();
long elapsed = now - lastRefillTime;
// 补充令牌
tokens = Math.min(capacity, tokens + elapsed * refillRate);
if (tokens >= 1) {
    tokens--;
    process(); // 获取令牌,处理请求
} else {
    reject(); // 令牌不足,拒绝请求
}
lastRefillTime = now;

2.3.4 算法对比

特性 计数器 漏桶 令牌桶
实现复杂度 低 中 中
内存占用 低 低 低
突发处理能力 弱(窗口临界问题) 弱(强制平滑) 强(允许累积令牌)
输出速率 不固定 严格固定 平均固定,允许突发
催收推荐度 ⭐(不推荐) ⭐⭐⭐⭐(通道限流) ⭐⭐⭐⭐⭐(通用推荐)
三种限流算法核心流程对比 计数器算法 固定时间窗口 计数器累加 超阈值则拒绝 窗口结束重置 漏桶算法 请求入桶(水滴) 桶满则丢弃 固定速率漏出 平滑处理请求 令牌桶算法 固定速率生成令牌 令牌可累积(突发) 请求消耗令牌 令牌不足则拒绝 催收触达API算法选型建议 • 计数器:仅适用于非关键路径的简单限流,如日志上报接口,不推荐用于核心催收通道 • 漏桶算法:适合短信、语音等有严格发送速率限制的通道,可避免被运营商封禁 • 令牌桶算法:推荐作为API网关的默认限流算法,兼顾平滑与突发处理能力 • 生产环境建议:令牌桶 + 漏桶组合使用,网关层用令牌桶,通道层用漏桶 • 阈值设定:参考历史峰值流量的1.5倍作为上限,预留缓冲空间
生产建议:在催收触达API网关层,推荐使用令牌桶算法作为主要限流策略。它既能应对催收任务批量下发时的突发流量(如上午9点批量发送提醒短信),又能保证长期平均速率不超过通道承载能力。对于下游的短信、语音通道,建议叠加漏桶算法,严格限制输出速率,避免触发运营商侧的限频策略。