架构深度学习

3.6:服务熔断设计

2020-05-22  本文已影响0人  今年花开正美

本文将梳理微服务架构下,服务熔断原理与设计。整体包含以下两部分:

为什么需要服务熔断

熔断场景

先定义两种角色,上游服务(服务调用方),下游服务(服务发布方)。一般而已,上游服务和下游服务是分开部署的,上游服务通过远程调用的方式来使用下游服务功能。

基于网络通信过程中的不确定性,有时上游服务调用下游服务可能出现如下四种情况:成功、失败、超时、拒绝。

在出现失败、超时、拒绝时,若不做处理,将有可能出现以下几种问题:

  1. 因单个服务故障导致系统雪崩,上游服务调用下游服务超时超时将增加请求的RT(Response Time),在系统高峰期请求将阻塞在上游服务进而导致上游服务也出现故障。
  2. 请求响应的结果是不可控的,用户收到的可能是超时、失败、拒绝等不可理解的错误信息。

因此在这种情况下,上游服务要有能力来对出现问题的下游服务进行熔断,也就是对有问题的下游服务不进行访问,而直接将将结果进行降级处理。

熔断设计

基于对场景的分析,可以知道熔断最基本的几个功能:

  1. 需要知道下游服务的调用结果。
  2. 可以根据调用结果判断是否开启熔断。
  3. 自定义降级内容,某个服务或接口开启熔断后,所有对该服务的请求都不在调用下游服务,而直接返回自定义的降级内容。
  4. 自动关闭熔断,下游服务不会一直处于故障状态,在下游恢复后需要能自动的关闭熔断。

下面我们就来看看Hystrix是怎么设计实现熔断的把。

Hystrix熔断的设计

Hystrix不仅仅是熔断器,他是专门用来保护服务调用过程中的各种问题。主要包括了服务线程池隔离,请求缓存,请求合并,以及最重要的熔断和降级。

本文重点分析熔断和降级的设计,其他内容请自行了解。

指标衡量工具:HystrixCommandMetrics

在Hystrix中,每一个Command对应一个断路器,每个断路器都有对应的HystrixCommandMetrics来负责结果统计、熔断的判断。

在HystrixCommandMetrics中最核心的功能就是维护了滑动时间窗口(t)内的若干个桶(n),每个桶统计(t/n)秒内的统计结果。默认t=1s,n=10。

熔断结果统计设计图

如上图所示,每个桶有四个统计值,分别是:

断路器主要使用HystrixCommandMetrics下面两个方法来判断是否打开。

<font color=red>
虽然HystrixCommandMetrics维护了一个滑动时间窗口内的n个桶数据,但是Hystrix却只使用了最新一个桶来作为判断的依据。
</font>

断路器:HystrixCircuitBreaker

HystrixCircuitBreaker是熔断实现的核心类,包括四个重要属性:

断路器的所有方法都是围绕上述四个属性来实现的,下面我们就详细分析下断路器的核心方法

allowRequest()

Hystrix在调用下游服务之前,首先调用该方法判断是否允许请求,若返回false,则直接走降级逻辑(Fallback)。

下面我们分析下allowRequest()的主要流程:

  1. 熔断开关是否强制打开,是则返回false,否则走下一步。

  2. 熔断开关是否强制关闭,是则返回true,但是返回true之前还是会调isOpen()走断路器的计算逻辑,用来模拟熔断打开/关闭行为。

  3. 调isOpen()和allowSingleTest()方法,这里代码(!isOpen() || allowSingleTest())有的拗口,总结下就两种情况:

    熔断开关是关闭时,则allowRequest()直接返回true,允许请求。
    熔断开关是打开的,则走allowSingleTest()逻辑,检查当前是否可以进行下一次探测了。
    

isOpen()

该方法专门用来判断断路器是否打开,具体流程如下:

  1. 熔断开关(circuitOpen)是否打开,也就是已经处于熔断状态了,则直接返回true。
  2. 获取最新一个统计桶。
  3. 判断请求总量是否小于设置的阈值,是则返回false。
  4. 判断错误率是否小于设置的阈值,是则返回false,否则进入下一步。
  5. 到这里说明需要打开熔断开关了,通过CAS来设置熔断开关为true。设置成功,则将circuitOpenedOrLastTestedTime设置为当前时间。
  6. 返回熔断开关为打开。

allowSingleTest()

该方法主要是在熔断开关打开的状态下,不断的在达到了探测时间时,临时放行一个请求到下游服务。主要就以下两步:

  1. 判断(circuitOpenedOrLastTestedTime+设置的探测时间)是否小于当前时间,是则说明已经可以进行下一次探测(临时放行这次请求)了。
  2. 在上一步为是时,重新更新circuitOpenedOrLastTestedTime的值,以供下次使用。

markSuccess()

在每次调用下游服务成功后,都调用该方法来将熔断开关关闭。主要以下两步:

  1. 若熔断开关是打开的,则将开关关闭。
  2. 重置指标衡量数据。

Hystrix的熔断设计还是比较清晰的,主要代码里面使用了大量的RxJava类库,不熟悉的话看代码还是比较吃力。

最后我们看下官方提供的熔断器判断流程图:

服务熔断设计流程图
上一篇下一篇

猜你喜欢

热点阅读