xiaobaoqiu Blog

Think More, Code Less

Api Blocking

1.背景

接口限流是保证系统稳定性的三大法宝之一(缓存, 限流, 降级).

本文使用三种方式实现Api限流, 并提供了一个用Spring实现的Api限流的简单Demo, Demo的git地址: https://github.com/xiaobaoqiu/api-blocking

其中接口限流配置在文件 blocking-config.properties 中, 内容实例如下:

1
2
3
4
5
6
7
8
9
10
11
# 每一块审核一个限流配置,一块内的起始数字相同,数字依次往下递增
# 每一块由一下四个信息组成:
#   name - 请求url
#   redirectUrl - 请求被阻塞的时候跳转的 url
#   duration,limit - 在 duration 秒的时间内最多访问 limit 次

# 表示接口 /business/detail.json 10 秒只能被访问 2 次, 超过的请求讲被跳转到 /noAuth 上
0.url=/business/detail.json
0.redirectUrl=/noAuth
0.duration=10
0.limit=2

里面包含了三种方式来实现限流, 下面将主要审核分别详细介绍三种方式:

1.Redis
2.滑动窗口
3.Guava的RateLimiter

2.Redis实现限流

Redis的官网的命令手册的例子就是如何使用 incr 指令实现接口限流.参见官网: https://redis.io/commands/incr/

简单说就是每个请求生成一个key(可以根据IP + 接口url生成, 也可以直接根据接口url生成), value为计数值. 设置过期时间.

需要注意 Redis 的过期策略是混合的:

1.被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key;
2.主动删除:Redis会定期(默认好像是100ms)主动淘汰一批已过期的key;当已用内存超过限定时, 也会触发主动清理策略;

3.滑动窗口实现限流

大家都知道TCP中的滑动窗口有调节发送速率的作用.这里是一个类似的想法.

按照我们的配置, 我们期望 duration 时间内最多 limit 个请求, 我们可以想象有一个事件窗口, 其宽度就是 duration, 因为每个请求都有一个时间戳(可以用Long表示), 每次请求过来的时候, 我们只需要校验当前请求为尾端的时间窗口内的请求数目是否满足 limit 需求就行了.

实现很简单, 使用一个环形队列就行.具体参考 demo 代码.

4.RateLimiter实现限流

直接使用Guava提供的RateLimiter实现.

RateLimiter的原理参考: http://xiaobaoqiu.github.io/blog/2015/07/02/ratelimiter/