限流算法:漏斗算法和令牌桶算法
来历
这两个算法来源于计算机网络。在网络传输数据时,为了防止网络拥塞,需要限制网络中的流量,即限流
漏斗算法
水(大量并发的用户请求)进入漏斗里,漏斗以一定的速度出水。当水流入的速度过大也就是漏斗满了的话,直接进行溢出。
漏斗算法被认为是一种粗暴的限流算法,因为并不是所有情况下当前没抢到商品的请求都要被抛弃,因此这种强制性过滤算法并不具备灵活性
优点:能强行限制数据的传输速率
缺点:不灵活,漏桶算法不能够有效地使用网络资源
令牌桶算法
令牌桶算法原理如下:水(用户请求)必须拿到令牌才代表消费成功。而“令牌数”有一个初始值,令牌桶也有一个令牌存储上限,当桶中的令牌耗光后,令牌桶会以自定义的速度生产令牌,此时所有的水(用户请求)会进入阻塞状态,阻塞时间内如果得到了令牌就会消费成功,如果阻塞时间过了还没有得到令牌,请求会被抛弃。
当用户请求没有经过时,令牌桶本身会不断生产令牌,直到令牌达到上限为止。这样做的好处是,面对瞬时大流量,该算法可以在短时间内请求拿到大量令牌,支持了突发请求。
优点:突发传输
使用场景
漏桶算法:恒定速率流出,不支持突发流量。在依赖服务没有做限流的场景下,可以用于防止打垮我们依赖服务,因为第三方服务的最大水位及其在最大水位可持续服务多长时间,对上层服务是未知的。
令牌桶算法:恒定速率流入,可以支持突发流量。通常突发流量最大值对于我们自己维护的服务是清晰可控的,为保证系统的最大可用性(尽可能处理更多的请求),同时防止自己的服务被打垮,优先使用令牌桶算法。
Java使用
Guava中开源出来一个令牌桶算法的工具类RateLimiter,可以轻松实现限流的工作。
1、引入相关的依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
2、Demo
public class RateLimiterTest {
public static void main(String[] args) throws InterruptedException {
RateLimiter limiter = RateLimiter.create(10);
Thread.currentThread().sleep(1000);
if (limiter.tryAcquire(20))
System.out.println("======== Time1:" + System.currentTimeMillis() / 1000);
Thread.currentThread().sleep(1001);
if (limiter.tryAcquire(1))//代码3
System.out.println("======== Time2:" + System.currentTimeMillis() / 1000);
if (limiter.tryAcquire(5))
System.out.println("======== Time3:" + System.currentTimeMillis() / 1000);
}
}