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网关层,推荐使用令牌桶算法作为主要限流策略。它既能应对催收任务批量下发时的突发流量(如上午9点批量发送提醒短信),又能保证长期平均速率不超过通道承载能力。对于下游的短信、语音通道,建议叠加漏桶算法,严格限制输出速率,避免触发运营商侧的限频策略。