文章目录
1. 我们为什么需要限流
在上一篇架构师成长之路之服务治理漫谈里面,我们已经谈到了高可用治理的部分,为了“反脆弱”,在微服务复杂拓扑的情况下,限流是保障服务弹性和拓扑健壮的重中之重。想想,如果业务推出了一个秒杀活动,而你没有任何的限流措施,当你搭建了一个账号平台,而完全没有对十几个业务方设定流量配额,这很有可能在特定场合下给你的产品带来大量的业务损失和口碑影响。我们通常重点关注产品业务层面正向和逆向功能的完成,而对于逆向技术保障则是企业发展过程中很容易忽视的点,所以一旦业务快速增长,这将给你的产品带来很大的隐患。当然,也不是所有的系统都需要限流,这个取决于架构师对于当前业务发展的预判。
2. 我们常见的限流手段
我们列举业内比较常见的一些限流手段:
2.1 信号量计数
信号量竞争是用来控制并发的一个常见手段。比如C和Java中都有Semaphore的实现可以让你方便地上手。鼎鼎大名的弹性框架hystrix也默认选择了信号量来作为隔离和控制并发的办法。他的优点即在于简单可靠,但是只能在单机环境中使用。
2.2 线程池隔离
隔离舱技术中也大量使用了线程池隔离的方式来实现,通过限制使用的线程数来对流量进行限制,一般会用阻塞队列配合线程池来实现。如果线程池和队列都被打满,可以设计对应拒绝策略。需要谨慎调整其参数,和线程池隔离的个数,以避免线程过多导致上下文切换带来的高昂成本。也是基于这个考虑,hystrix默认采用了信号量计数的方式来控制并发。 同样,其也只能在单机环境中使用。
2.3 固定窗口计数
我们可以以第一次请求访问的时候开始进行计数,而不严格按照自然时间来计数。比如可以利用Redis的incr和expire组合进行计数,如下伪代码所示:
count = redis.incrby(key)
if count == 1
redis.expire(key,3600)
if count >= threshold
println("exceed...")
这种实现方式简单粗暴,可以解决绝大部分分布式限流的问题。但是其存在的问题:
- 该计数方式并不是准确计数,由于时间窗口一旦过期,则之前积累的数据就失效,这样可能导致比如本来希望限制“一分钟内访问不能超过100次”,但实际上做不到精准的