在分布式系统中,如果某个服务节点发生故障或者网络发生异常,都有可能导致调用方被阻塞等待,如果超时时间设置很长,调用方资源很可能被耗尽。这又导致了调用方的上游系统发生资源耗尽的情况,最终导致系统雪崩。
如下图:
如果D服务发生了故障不能响应,B服务调用D时只能阻塞等待。假如B服务调用D服务设置超时时间是10秒,请求速率是每秒100个,那10秒内就会有1000个请求线程被阻塞等待,如果B的线程池大小设置1000,那B系统因为线程资源耗尽已经不能对外提供服务了。而这又影响了入口系统A的服务,最终导致系统全面崩溃。
提高系统的整体容错能力是防止系统雪崩的有效手段。
在Martin Fowler和James Lewis的文章 《Microservices: a definition of this new architectural term》中,提出了微服务的9个特征,其中一个是容错设计。
要防止系统发生雪崩,就必须要有容错设计。如果遇到突增流量,一般的做法是对非核心业务功能采用熔断和服务降级的措施来保护核心业务功能正常服务,而对于核心功能服务,则需要采用限流的措施。
今天我们来聊一聊系统容错中的限流、熔断和服务降级。
当系统的处理能力不能应对外部请求的突增流量时,为了不让系统奔溃,必须采取限流的措施
1限流指标
1.1TPS
每秒事务处理量(TransactionPerSecond)
系统吞吐量是衡量系统性能的关键指标,按照事务的完成数量来限流是最合理的。
但是对实操性来说,按照事务来限流并不现实。在分布式系统中完成一笔事务需要多个系统的配合。比如我们在电商系统购物,需要订单、库存、账户、支付等多个服务配合完成,有的服务需要异步返回,这样完成一笔事务花费的时间可能会很长。如果按照TPS来进行限流,时间粒度可能会很大,很难准确评估系统的响应性能。
1.2 HPS
Hits Per Second
每秒请求数,指每秒钟服务端收到客户端的请求数量。
如果一个请求完成一笔事务,那TPS和HPS是等同的。但在分布式场景下,完成一笔事务可能需要多次请求,所以TPS和HPS指标不能等同看待。
1.3 QPS
Queries Per Second
服务端每秒能够响应的客户端查询请求数量。
如果后台只有一台服务器,那HPS和QPS是等同的。但是在分布式场景下,每个请求需要多个服务器配合完成响应。
目前主流的限流方法多采用HPS作为限流指标。
2 限流方法
2.1 流量计数器
这是最简单直接的方法,比如限制每秒请求数量100,超过100的请求就拒绝掉。
但是这个方法存在2个明显的问题:
单位时间(比如1s)很难把控,如下图:
这张图上,从下面时间看,HPS没有超过100,但是从上面看HPS超过100了。
有一段时间流量超了,也不一定真的需要限流,如下图,系统HPS限制50,虽然前3s流量超了,但是如果读超时时间设置为5s,并不需要限流。
2.2 滑动时间窗口
滑动时间窗口算法是目前比较流行的限流算法,主要思想是把时间看做一个向前滚动的窗口,如下图:
开始的时候,我们把t1-t5看做一个时间窗口,每个窗口1s,如果我们定的限流目标是每秒50个请求,那t1~t5这个窗口的请求总和不能超过250个。
这个窗口是滑动的,下一秒的窗口成了t2~t6,这时把t1时间片的统计抛弃,加入t6时间片进行统计。这段时间内的请求数量也不能超过250个。
滑动时间窗口的优点是解决了流量计数器算法的缺陷,但是也有2个问题:
流量超过就必须抛弃或者走降级逻辑
对流量控制不够精细,不能限制集中在短时间内的流量,也不能削峰填谷
2.3 漏桶算法
漏桶算法的思想如下图:
在客户端