cover_image

双十一技术攻略(三): 熔断实战

杨俊杰 张雷 达达集团技术 2017年12月29日 09:01

作者简介

杨俊杰,达达京东到家基础架构团队leader,致力于为达达平台提供高性能高可用的中间件和基础服务。张雷,达达京东到家基础架构团队软件开发工程师,对于熔断、监控、容灾等领域有深入研究。

1


背景

达达配送平台是复杂的分布式系统,由近百个Python服务和Java服务构成,业务复杂,服务间依赖也较多,出现了不少由于服务调用出现异常而导致的重大事故,如:

系统雪崩

系统依赖的某个服务发生故障或响应延迟,使其它服务的资源被耗尽,导致故障蔓延到整个系统。例如,在未接入熔断之前,达达系统中因为order服务出现故障,导致API和其它服务短时间也相应产生报警,接下来整个系统不可用。


数据库读写压力

虽然达达系统是向微服务演进的系统,但是因为历史的遗留,多表耦合在某个库中,数据库因为写入压力过大而崩溃,需要在系统负载到一定程度上能够缓解数据库读写的压力。

针对系统的痛点,我们把熔断技术引入到达达系统中,经过几个月的改进,研发出一套适合达达自己的熔断技术,从而保障了双十一期间每天支撑高达八百万订单而系统坚如磐石。





熔断就是在系统资源耗尽时,对继续访问的请求执行快速失败逻辑,不再执行正常的业务逻辑,为服务减压,待服务恢复稳定后,重新允许请求执行正常的业务逻辑





2


技术选型

为了保护系统,需要根据系统的特点和需求来选择合适的技术。首先,达达系统是包括Python和Java的系统,不是单一技术体系的系统;其次,达达系统是向微服务演进的系统,系统的承载压力处于时时变化中;第三,需要有合适的保护策略,简单好用;最后,我们希望能监控到引入的技术是否真正保护了系统。

根据这些特点和需求,我们整理出熔断需要遵守以下原则:

支持Java和Python系统


熔断参数可动态配置


熔断策略简单易用


熔断效果可监控 


尽可能不影响用户体验

考虑这些因素,Netflix的Hystrix熔断技术比较符合我们的选型要求。虽然Hystrix只用于Java系统,但是它的设计思想非常好,可以借鉴它的设计思想,实现Python系统的熔断,也可以在Hystrix的源码基础上改进满足动态配置的效果。

Hystrix依赖的熔断隔离架构,如下图(供读者参考):

图片

Hystrix通过将每个依赖服务分配独立的线程池进行资源隔离,从而避免服务雪崩。比如当商品评论服务不可用时,即使商品评论服务独立分配的20个线程全部处于同步等待状态,也不会影响其他依赖服务的调用。


3


设计思想

Hystrix是很不错的熔断技术,接入简单,在业界也应用广泛。关于Hystrix的应用,可以参考官方文档。但是根据上文提到特定需求,我们主要是借鉴Hystrix的思想,在Java熔断上对Hystrix做了改进,在Python熔断根据其思想自主研发。设计思路如下:

断路器


        断路器实现了系统的异常保护功能,请求执行失败后(异常或者超时),会执行断路检测功能,如果接口的超时数量超过某个阈值,或者异常占比超过某个比例,断路器会认为当前接口已经发生异常,如果继续访问可能会对系统造成雪崩问题,会将断路器置于半启动状态,如果下一次请求失败,则打开断路器,在接下来的N(可配置)秒内,所有访问该接口的请求会快速失败,给服务减压,并在N秒后,尝试关闭断路器,允许下一次的请求进行正常访问,如果此请求依旧超时或者抛出异常,则认定系统依旧处于不可用状态,继续在接下来的N秒内打开断路器,并在N秒后重新进行尝试,重复进行该步骤,直至请求可以正常访问,此时断路器会认为系统已经恢复正常,则清空原有计数器数据,关闭断路器。

熔断保护

   

请求超时熔断

熔断器中有一个超时计数器模块,当请求超时,计数器加1,请求正常,计数器减1,如果系统某个时刻发生异常,接口响应变慢,导致超时计数器计数超过阈值N(可配置),会触发熔断的超时保护功能,断路器功能触发,以达到保护系统的作用。


业务异常熔断

熔断器中有一个请求计数模块,请求计数器会区分正常请求和异常请求(超时的请求也当做异常请求),计数器是以时间滑动窗口的形式实现,默认10s的滑动窗口,每秒单独生成一个计数桶,如果最近10s内的错误请求占比超过某个阈值N%(可配置),并且10s内请求数量高于最低允许的请求量x(可配置),则熔断器认为当前接口发生异常,会触发断路器打开,保护系统。


快速失败  

请求异常快速失败

如果请求执行过程中产生异常,并且该异常没有被熔断器标记为可忽略的异常,则熔断器会捕获抛出的异常,然后执行fallback逻辑,并在熔断计数器中对错误数量递增,断路器会计算计数器中的数据,如果符合断路触发条件,则打开断路器,拒绝请求。


流量超限快速失败

熔断器根据请求计数模块中的数据进行了限流熔断,如前文所述,计数器中会每秒生成一个计数桶,每次请求会检查当前计数桶中的tps,如果当前桶中的请求量超过配置的阈值N,则认为当前访问量过高,在这1s内接下来的时间,所有访问该接口的请求都会快速失败,接口会在下一秒重新恢复正常。


熔断恢复

    接口熔断后,会在N秒(熔断时间,可配置)后重新尝试接收请求,如果请求依旧失败,则重新打开断路器,如果请求成功,则关闭断路器,清空计数器,允许请求的正常访问。

动态配置

    在接口刚刚上线阶段和系统演进的过程中,很多阈值初期很难准确给出的,比如超时时间、流量超限等,基于这个原因,加入了熔断器的动态配置功能,只需要在配置中心中配置新的值,并进行配置下发,熔断器在下次请求中会自动重载所有配置。

注解支持

    使用装饰器方式为接口添加熔断功能,方便开发人员接入,只需要在接口上添加注解即可@circuit(配置内容)。

熔断监控

    将熔断的触发、接口的失败、超时、回退等信息统一上报到监控系统,实现了熔断的监控和报警功能。


4


熔断实现

       

     因为达达系统是Java和Python混合的分布式系统,分别对Java和Python做了相应的处理。对于Java系统主要对Hystrix增加动态配置和监控,即可满足上面的设计思想。对于Python系统,根据以上设计思想自主开发了Python的熔断。


Java系统熔断实现

在Hystrix源码中,实现动态配置,通过加入onValueChanged()进行配置变更的监听,使其请求时如果配置发生变更进行reset操作并读取当前的配置。代码如下:

图片

有了动态配置的策略,我们不必担心熔断设值的问题,可以在系统运行中根据监控来适当调整熔断值。下面是我们接入熔断的例子。

图片

其中dynamicKey即是动态配置的值,开发人员可以在配置中心中动态的调整相应的熔断值,使熔断达到最佳的效果。

对于熔断的监控,我们通过servlet的filter方式,在拦截器中拦截Hystrix,并监控Hystrix状态,通过在日志中打印"Hystrix Request Data"的特定字段,方便在日志中收集,用来监控熔断的效果。如下代码所示:

图片

图片


特定的logger将写入日志文件,由flume收集,经过处理传入达达监控系统,监控熔断的效果。


Python熔断的实现

对于Python系统的熔断接入,如上文所提到的,我们也根据Hystrix的思想开发了相应的熔断。首先介绍python熔断器的策略:在断路器未打开状态时检查相应跟踪的参数,如超时、异常,在错误率或超时超过相应的熔断阈值时,将断路器置于半启动状态,根据半启动状态时监控到的数据,进行相应的操作,比如熔断、回退或是恢复。核心代码如下:当请求因超时或执行异常后,便会执行如上所示的代码:

图片其中主要执行逻辑如下

    1. 判断当前断路器是否处于半启动状态,如果是,则打开断路器,如果为否,继续执行如下第2步或者第3步的判断。

    2. 如果当前滑动时间窗口(默认10s)内的请求数量超过允许断路的最低请求量,则判断当前滑动时间窗口内的请求错误率是否超过阈值,如果超过阈值,将断路器设置为半启动状态。

    3. 判断请求超时数量是否超过阈值,如果超过阈值,将断路器设置为半启动状态。

    4. 判断当前滑动时间窗口中当前时间桶的回退请求是否超过阈值,如果超过,请求直接抛出,不再执行回退逻辑。

    5. 记录各个事件并上报到监控系统,最终展现到熔断监控中。


5


熔断的影响

熔断是对系统保护,那么它对系统有什么影响呢?

一般来说,主要有以下几方面的影响:

用户体验

从上文的介绍大家可以看到其实系统熔断时,一些请求是不可访问的,对于用户体验方面是有些影响的。为了降低对达达用户的影响,我们主要对数据写入的操作添加了熔断,对读取的操作不做限制,因为DB的压力主要是数据写入的压力。这种设计对于达达配送员来说,订单获取不受到影响,配送员可以正常配送;对于订单完成时,要更改状态,可能偶尔会有一次不成功,但是不影响他的下次接单操作,配送员只需要再操作一次即可。因为手机网络在移动时并不是非常稳定,配送员可能认为是网络问题,心理上也易于接受。


数据一致性

一般来说,不同服务之间业务代码要对异常进行相应的处理,保证上下文服务的返回数据一致,这样即使发生了熔断,但是转入了异常处理逻辑,对数据一致性也没有损害。因而在接入熔断时,我们根据以前业务代码对异常错误的处理,把回退相关的操作接入到相应的异常处理中,保证了整个系统数据的一致。



6


熔断在双十一期间的表现

那么接入了熔断后在对系统稳定性有什么样的效果呢?根据我们的监控,熔断实实在在保护了达达系统。自从熔断接入后,系统相当稳定,雪崩现象不再发生,即使某个服务频繁报警也不会对系统产生严重影响。在双十一期间,熔断也时时刻刻保护系统,下图的数据表示在11.11日在11:00-12:00的高峰期,每分钟API熔断次数在1000~3000次,熔断在保护系统中起到了巨大的作用。

图片



6


结束语

达达系统的熔断在八月底接入平台,在双十一之前不断进行改进,形成了达达特色的熔断技术,也在双十一期间经受住了考验,为平台的稳定贡献了力量。欢迎对达达技术感兴趣的朋友与我们探讨,知识和技术都是在讨论中不断进步。


号外:达达-京东到家北京、上海、成都的研发中心正在大力招聘优秀工程师,欢迎入伙。北京、成都投简历至cvbj@imdada.cn ,上海投简历至cv@imdada.cn。


图片

继续滑动看下一个
达达集团技术
向上滑动看下一个