美文网首页java
基于滑动窗口的消息静默限流

基于滑动窗口的消息静默限流

作者: zqrferrari | 来源:发表于2017-07-17 16:57 被阅读529次

    1、背景


    在物流详情的数据监控应用中,会通过消息中间件来接收包裹物流的变更消息(qps均值在1w,峰值在4w),接收到消息之后会调用一个后端的定时触发的服务(TMQ)用来检测物流消息是否及时回传。

    正常情况下,后端TMQ服务的接口rt在20ms左右,整个设计和架构上运行正常。但是由于TMQ是一个公共的服务,上面承载了很多其他业务方的应用,特别是一些营销类的应用,在活动期时TMQ的定时任务被大量触发,而物流详情是一个最大的使用方。多种场景的叠加导致TMQ变得非常不稳定,反应到业务上就是接口rt飙升,处理能力下降,TMQ维护同学为了避免自己的应用被压死会选择性的降级掉我们的接口。

    TMQ接口rt

    因此在方案上考虑通过检测TMQ接口性能,当发现其接口性能下降时进行统计分析,达到一定阈值则自动降级掉对TMQ的调用,同时在降级之后对metaq采取静默限流,利用metaq的抗堆积能力,在限流期间不把流量压到后端,为TMQ的恢复争取一点时间。静默限流期过后,再恢复对TMQ的调用请求,并继续监测接口性能,如果到阈值则再次降级并进行静默限流,如此反复,直到后端的服务恢复到正常状态。

    2、服务依赖的稳定性


    在互联网服务中,一个稍微复杂点的应用都需要依赖很多后端的服务,服务端基本都是分布式的,大量的服务支撑起整个系统,服务之间也难免有大量的依赖关系。而依赖的后端服务并不是100%稳定,也不是所有依赖都是核心依赖,在依赖的后端服务不稳定时,如果避免影响到自身服务,防止被拖死,需要在设计上有所考虑。

    在系统的高可用设计中,针对后端服务的依赖,有非常重要的两条:

    • 接口超时
    • 服务熔断

    接口超时大家都非常的熟悉,任何一个通过网络进行的请求都必须设置正确的超时时间,因为一次网络请求都对应了一个线程或者进程。如果请求被处理的太慢而又没有对这次请求设置超时,那么自身应用的线程就会被拖死,短时间得不到释放,线程是昂贵的系统资源,进而导致服务资源被耗尽,自身服务不可用。

    服务熔断的灵感来源去于断路器或者保险丝。断路器或者保险丝的作用是当电流过载或者短路的时候会自动断开,避免由于电路不断开,电线升温,造成火灾,引起更大的灾难。

    应用到系统设计中,如果我们自己的应用依赖的某个后端服务不稳定,有大量的超时,再让新的请求去访问已经没有太大意义,那只会无谓的消耗现有资源。例如即使已经设置超时1秒了,那明知依赖不可用的情况下再让更多的请求,比如100个,去访问这个依赖,也会导致100个线程1秒的资源浪费。

    断路器可以避免这种资源浪费,在自身服务和依赖之间放一个断路器,实时统计访问的状态,当访问超时或者失败达到某个阈值的时候(如50%请求超时,或者连续20次请失败),就打开断路器,那么后续的请求就直接返回失败,不至于浪费资源。断路器再根据一个时间间隔(如5分钟)尝试关闭断路器(或者更换保险丝),看依赖是否恢复服务了。

    2.1 Hystrix

    方案上需要对后端服务进行监控,在后端服务发生问题时进行隔离。
    这里就涉及到两个个问题:

    • 如何发现问题,监控后端的什么指标来判断后端服务发生了问题。
      这里是采用监控后端服务接口的rt,并记录调用后端服务接口的次数,以及rt超过阈值(1000ms)的次数, 如果在一定时间内rt超时的次数和请求次数的比值大于一个阈值则认定后端服务有问题,需要对其进行隔离。

    • 如何恢复,在监控到产生问题,对后端服务进行隔离之后,何时开始恢复。
      同上,也是监控接口请求次数以及超时次数,如果一定时间内容两者的比值小于一个阈值,则认为后端服务开始恢复,撤销对其的隔离。

    Hystrix是Netflix开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟、异常,引起资源耗尽导致系统不可用的解决方案。

    Hystrix的官方介绍:https://github.com/Netflix/Hystrix

    在具体的方案实现上没有直接接入Hystrix,原因是Hystrix的使用还是稍显复杂,接入成本偏高。最终实现上借鉴了Hystrix滑动窗口,用来监控和处理一定时间内接口的性能

    2.2 Hystrix滑动窗口

    Hystrix滑动窗口设计的关键在于其高效的无锁统计。

    在统计指标项时,如果每个周期都从零开始统计,那么会得到一个周期性出现锯齿的统计曲线,在系统层面上会表现为对依赖的服务造成herd effect(羊群效应/从众效应)。

    因此,Hystrix将一个统计周期分解为更小的段(bucket),通过移动时间窗口淘汰最老的bucket。

    Rolling Window

    每当需要开始一个新的bucket时,牺牲可容忍的准确性,通过tryLock由一个线程去更新,其他线程依然使用最近的bucket来更新计数。

    Rolling Window

    每个bucket使用LongAdder而不是AtomicLong进一步降低写的并发,减少执行CAS时循环的次数。

    3、静默限流


    3.1 metaq静默限流

    方案上,后端服务进行隔离之后,由于消息无法得到处理也不能丢失,因此需要对metaq进行控速,在隔离期间不让流量打过来而是堆积在metaq中,等服务恢复之后再进行处理。

    使用的方法是在发现接口被熔断之后,使metaq的消费线程sleep一段时间,sleep时间过去之后再次请求后端服务,同时在之后的流程中再次确定接口是否被熔断,知道后端服务完全恢复。

    3.2 最终的实现

    handleLecMsg(...)是metaq消费线程处理消息的方法,其中会记录对TMQ接口请求的次数以及超时的次数,达到阈值则熔断开始静默限流。


    最终实现

    相关文章

      网友评论

        本文标题:基于滑动窗口的消息静默限流

        本文链接:https://www.haomeiwen.com/subject/pchqkxtx.html