第一,限流方案必须是可选的,没有任何方案可以适用所有场景。第二,限流策略必须是可配置的。
集中常见的限流方式:
- 通过限制单位时间段内的调用量来限流。
- 通过限制系统的并发调用程度来限流。
- 通过漏桶(Leaky Bucket)算法来限流。
- 通过令牌桶(Token Bucket)算法来限流
限制单位时间的调用量
通过一个计数器来统计单位时间内某个服务的访问量。如果超过了阙值,则该单位时间段那不允许继续访问,或者把请求放入队列中等下一个时间段继续访问。
单位时间不能太长,太长将导致限流效果不够“敏感”。比如我们的监控系统统计的事服务每分钟的调用量,所以很自然我们可以选择 1 分钟作为时间片段。
对于限制单位时间段内调用量的这种限流方式,实现简单,适用于大多数场景,如果阀值可以通过服务端动态配置,甚至可以当作业务开关来使用
但是也有一定的局限性,如果设定的阀值在单位时间段内的前几秒就被流量突刺消耗完了,将导致该时间段剩余的时间内该服务“拒绝服务”,这种现象被称为“突刺消耗”,并不常见。
限制系统的并发调用程度
我们通过并发限制来限流,我们通过严格的限制某服务的并发访问速度,其实也就限制了该服务单位时间段内的访问量。
并发限流一般用于服务资源有严格的限制的场景,比如连接数,线程数等。但是也未尝不能用于通用的服务场景。
从表面上看并发限流似乎很有作用,但也不可否认,它仍然可以造成流量尖刺,即每台服务器上该服务的并发量从 0 上升到阀值是没有任何阻力的,因为并发量考虑的只是服务能力边界的问题。
漏桶(Leaky Bucket)算法
漏桶算法事流量整形或者限流的常用算法之一。它有点像我们生活中用到的漏斗,液体倒进去以后在小口中以固定速率流出。漏桶算法就是这样,不管流量有多大,漏桶都保证了流量的常速率输出。既然是一个桶,那么肯定有容量,由于调用的消费速率已经固定,那么当桶的容量堆满了,则只能丢弃了。
令牌桶(Token Bucket)算法
令牌桶算法中,桶中会有一定数量的令牌,每次请求调用需要去桶中拿取一个令牌,拿到令牌后才有资格执行,否则必须等待。
有的同学或许有些疑问,如果把令牌比喻成信号量,那么好像和并发限流没什么区别嘛。
其实不是,令牌桶算法的精髓在于拿令牌和放令牌的方式,这和单纯的并发限流有明显的区别,因为每次请求时需要获取的令牌数不是固定的,比如当桶中的令牌比较多时,每次调用只需要获取一个令牌,随着令牌数的逐渐减少,当令牌使用率(使用中的令牌数/令牌总数)达到某个比率时,可能一次需要获取两个令牌,获取令牌的个数可能还会升高。归还令牌有两种方法,第一种是直接放回,第二种是什么也不做,有另一个额外的令牌生成步骤将令牌允许放回桶中。