一、高并发场景下服务雪崩问题
在分布式、微服务系统中,完成一个请求需要多个微服务共同完成,我们可以把一个调用链上的两个上下游微服务分为:调用方与服务提供方
如果某个“服务提供方”发生故障或者网络发生异常,都有可能导致“调用方”被阻塞等待,
如果“调用方”超时时间设置很长,调用方资源很可能被耗尽。这又导致了调用方的上游系统发生资源耗尽的情况,最终导致系统雪崩。
问题来了:调用方的超时时间设置很长,在原地一直等着就好了,为啥会把自己的资源耗尽呢???
举例如下图
调用方:B
服务提供方:D
如果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》[1]中,提出了微服务的9
个特征,其中一个是容错设计。
要防止系统发生雪崩,就必须要有容错设计。
如果遇到突增流量,一般的做法是
1、对非核心业务功能采用熔断和服务降级的措施来保护核心业务功能正常服务,
2、而对于核心功能服务,则需要采用限流的措施。
总结:限流、熔断与降级,此三者都是流量过大时,通过一定的方式去保护系统的手段,是应对海量服务的三大“神器”
三、限流
3.1 什么是限流
限流是从系统的流量入口考虑,当系统的处理能力不能应对外部请求的突增流量时,为了不让系统奔溃,从进入的流量上进行限制,达到保护系统的作用,只允许系统能够承受的访问量进来,超出的会被丢弃
如何判断承受不了呢?通过设置阈值例如tps、qps达到一定的阈值,则触发限流
3.2 限流的方法-令牌桶
场景的限流方法有很多,例如流量计数器、滑动时间窗口、漏桶算法、令牌桶算法
此处我们主要介绍令牌桶算法,这也是应用比较多的一种限流方法
令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
令牌桶算法就跟病人去医院看病一样,找医生之前需要先挂号,而医院每天放的号是有限的。当天的号用完了,第二天又会放一批号。
优点:
-
放过/放行的流量比较均匀,有利于保护系统。
-
存量令牌能应对突发流量,很多时候,我们希望能放过脉冲流量。而对于持续的高流量,后面又能均匀地放过不超过限流值的请求数。
缺点:
-
存量令牌没有过期时间,突发流量时第一个周期会多放过一些请求(因为此时桶内的令牌必然是满的),可解释性差。
-
实际限流数难以预知,跟请求数和流量分布有关。
要想预知限流的请求数可以采用QPS限流算法(QPS 限流算法通过限制单位时间内允许通过的请求数来限流。),但该算法放行的流量不均匀
有兴趣进一步了解可以看这里:https://help.aliyun.com/document_detail/149952.html
四、降级
限流则从用户访问压力的角度来考虑如何应对故障,而降级从系统功能优先级角度考虑如何应对故障,是站在系统全局的视角来考虑问题的
降级也就是服务降级,当我们的服务器压力剧增时,为了保证核心功能的可用性 ,而选择性的降低服务自身的一些不重要的功能,或者直接关闭该功能。
所以降级降的是非核心业务组件,这就是典型的丢车保帅了。
当服务暂时不可用或者影响到核心流程时,需要待高峰或者问题解决后再打开
五、熔断
降级是应对系统自身的故障,而熔断的熔断的是对外部系统的访问,因为外部服务可能挂掉了!
比如保险丝,当电流过大时,就会熔断,从而避免元器件损坏
A服务的X功能依赖B服务的某个接口,当B服务接口响应很慢时,A服务X功能的响应也会被拖慢,进一步导致了A服务的线程都卡在了X功能上,A服务的其它功能也会卡主或拖慢。此时就需要熔断机制,即A服务不再请求B这个接口,A服务内部发现B接口就直接返回错误,从而避免整个A服务被拖慢。
- 实现思路:需要系统有一个统一的API调用层,由API来进行采样或者统计。
六、举例
如果你来设计一个整点限量秒杀系统,包括登录、抢购、支付(依赖支付宝)等核心功能,你会如何设计接口级的故障应对手段?
- 思路:
- 降级(丢车保帅):在秒杀时,通过服务降级把注册、修改个人信息等非核心功能关闭掉。
- 熔断:支付流程依赖第三方服务,而第三方服务不可控制、可能会访问超时,我们作为调用方要设置熔断策略,并且熔断后要给出友好提示,比如10分钟后再来支付。
- 限流:抢购下单接口采用限流方式,如抢购1000件商品,则设置2000大小的队列,请求超过2000后直接拒绝掉。
七、总结
限流、熔断和服务降级是系统容错的重要设计模式,从一定意义上讲限流和熔断也是一种服务降级的手段。
熔断和服务降级主要是针对非核心业务功能,而核心业务如果流程超过预估的峰值,就需要进行限流。
对于限流,选择合理的限流算法很重要,令牌桶算法优势很明显,也是使用最多的限流算法。
在系统设计的时候,这些模式需要配合业务量的预估、性能测试的数据进行相应阈值的配置,而这些阈值最好保存在配置中心,方便实时修改。