为什么需要限流
对于一个后端系统来说,其处理能力是有限的,会受到业务流程,系统配置等的限制,QPS和TPS有一个上限值,比如一个订单系统1分钟可以处理100个请求。当1分钟超过100个请求的时候,我们为了保证系统的可用性,就会采用限流设计,保证系统不会在过载的情况下,导致系统整体不可用。
实际应用场景中,比如北京的一些旅游经典会有预约模式,高铁购票也会排队进行买票。虽然可能导致后边用户买不到票,但是对于整个系统来说,可以正常处理可承载的容量。
软件设计中,数据库连接池,并发线程池等都有这样的设计。
限流策略
限流可以从整个链路上进行限制,比如从网关层以及服务端限流。这样像一个漏斗一样可以将较少的流量打到后端服务上。
限流的目的通过并发访问进行限制速率,一旦达到一定的速率就限制。
- 拒绝服务,直接将超过的请求进行丢弃,可以统计哪些客户端来的请求多,直接拒绝这个客户端,防止有恶意的高并发访问。
- 服务降级,关闭不重要的服务,将资源腾出来处理更多的用户请求,或者书数据层面返回部分数据等。预设缓存,可以通过降低数据一致性来提升性能。
- 特权请求,对于一些电商,或者是有VIP账号的业务系统来说,可以有限处理VIP的请求。但是一般都是多租户系统才会考虑。
- 延时处理,其实更多常见的是这种,就是将数据写入到异步消息队列中,然后下游系统按照自己的速率进行处理,对于大多数系统来说用户请求是比较宝贵的。但是这种一般也针对的是短暂的高峰请求
- 弹性伸缩,基础架构比较完善的系统可以自动化扩容机器,比如TOP3机器比较繁忙会自动进行伸缩,扩容机器部署服务。对于中小公司来说,大多数一个服务能搭建成集群就不错了。因为需要好的运维系统,自动化发布、部署和服务注册。
限流的实现方式
计数器方式
计数器方式比较简单,就是在一定的时间间隔内通过一个全局计数器,计算每个API接口调用次数。比如1分钟超过200个请求,则直接将后续请求丢弃。每1分钟counter就恢复为0.
缺点就是无法保证限流速率,如果突然某几S 进来300个请求,就会直接被击垮。
队列算法
一种比较常见的就是排队,也就是队列算法。
请求速率可以是波动的,但是处理的速度是非常匀速的,FIFO
比较简单,就是只要队列不满,就写入消息到Queue,然后下游系统处理。
优先队列
可以在上述基础上进行衍生,增加一个优先级队列。
优先级队列的优点是可以处理权重比较高的请求,但是可能会导致低优先级队列一直得不到处理,被饿死。
权重队列
权重队列 比较简单,按照一定权重处理 比如3:2:1 轮询处理,先处理权重3 3个请求,然后处理权重2 2个请求,接着就是权重1 1个请求。
队列流控是以队列方式处理请求,如果下游系统处理过慢,就会导致队列满,从而触发限流。
队列长度很难去衡量应该设置什么长度,过长可能导致队列还没满,服务服务已经挂掉。所以一般采用pull模式 而不是push。这样下游系统可以根据自己的消费速度进行处理。
漏斗算法 leaky Bucket
漏斗算法顾名思义就是一个漏斗一样,以恒定的速率进行请求和处理。当流量过大时就会积水,水太多就会溢出。
一般采用的是队列实现,请求过多时就积压请求,队列满就开始拒绝请求。TCP中就使用 sync backlog队列来缓冲请求。
那么和上述的队列算法比较 就是加了一个限流器。
令牌桶算法 Token Bucket
令牌桶算法 主要是假如一个中间人,会以一定的速率放入一些token, 处理程序需要先获取到token后才可以请求,否则没有就不处理。
可以看到,对比漏斗算法来说是以恒定的速率进行处理请求,而令牌桶则是流量小的时候攒钱,流量大的时候可以快速处理。
Processor因为有队列的存在,所以总能以最大处理能力来处理请求。
令牌桶可以做成一个公共服务,这样在分布式系统中就可以做全局的流控。
基于响应时间的动态限流
上述算法其实依赖一个系统最大的峰值,而这个值需要在生产系统进行性能测试,性能测试非常不容易,因为对于不同的用户可能Feed流,数据库,API性能等很难给出一个恒定值。所以就衍生除动态限流的方式,设计典范就是TCP协议的拥塞控制,实时计算系统性能,设定滑动窗口的大小。
我们可以计算10S内 P90或P99的响应时间。然后超过这个阈值就自动限流。
但是需要计算所有请求比较耗费内存和CPU,可以采用蓄水池算法,另一种就是采样计算。
限流的设计要点
限流的目的主要 保证系统的SLA,防止在多租户情况下系统的整体不可用。应对突发的流量。节约成本,不会为了一个不常见的尖峰扩容系统,而是在有限的资源下承受比较高的流量。
设计上
- 限流需要在架构设计初期就考虑好。
- 限流模块需要好的性能
- 限流应该有手动操作的开关。
- 限流发生 需要通过告警提示相关人员。
- 限流被拒绝的用户应该返回一个特定的错误码,可以和错误区分开来。走重试机制。
小结
本篇主要介绍了为什么需要限流设计,以及限流设计的常见 一般主要是为了保证系统的可用性,拒绝一部分用户。接着介绍了限流相关算法,计数器、排队、漏斗、令牌桶算法、动态限流算法等,然后说了下限流设计的要点。