微服务-API网关-熔断降级

介绍

在微服务架构中,各个服务之间往往是级联在一起的,一个服务发生故障时可能会造成以下灾难:

  • 服务依赖方调用超时,导致任务队列打满,引起链式反应,最终导致整个集群雪崩。
  • 服务依赖方调用返回失败,引起链式反应,最终导致整个集群不可用。

所以需要在微服务不可用时切断故障服务与其他服务的通讯。

熔断是对服务提供者说的,由于某些原因(比如网络不通、服务挂了、请求处理不过来)造成服务提供者不能提供服务时,服务提供者就需要切断和服务调用者的连接,不然就造成资源浪费或者队列打满,从而导致链式反应。

降级是对服务调用者来说的,当A服务调用B服务不通时,A服务就切断与B服务的通讯,同时采取降级措施,比如重试、返回空值,生成相应错误信息等。

设计目的

  • 隔离有故障的服务。
  • 停止复杂分布式系统中的级联故障。
  • 故障恢复后自动由隔离转为通行。
  • 在可能的情况下,后退并优雅地降级。
  • 启用近实时监视、警报和操作控制。

形态设计

以什么方式运行

我们应该以什么方式来运行熔断呢?微服务还是第三方库?

如果独立出来以微服务方式运行熔断器的话,有以下两方面问题:

  • 所有请求都要先通过熔断器服务,这样在网络IO上就是很大的开销,会造成网关整体性能的下降。

  • 不利于熔断状态的判断,比如由于队列满造成服务调用失败,这时就应该开启熔断器,但是如果熔断器是以微服务方式运行,这种情况就不好做。

所以最理想的方式是以三方库或者叫插件的方式来运行。

放在调用侧还是被调用侧

如果把熔断器放在被调用服务侧的话会有两方面的问题:

  • 依赖方需要和故障方通讯后请求才返回,增加了网络IO消耗,降低了网关整体性能。
  • 故障方可能整个挂掉了,连熔断器也不能用了,这样还是会导致整个网关雪崩。

架构设计

整体设计

流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FOvt5LIO-1598435903719)(/Users/zhanghh/Documents/doc/newbusiness/lessions/pictures/api-fusing-5.png)]

流程分析

  • 我们可以把熔断器要执行的内容套在API调用的外面,这样就隐藏了细节,简化了代码。
  • 第一步可以先看看这个请求是否可以用缓存数据,可以的话就直接从缓存里面读取数据返回。
  • 看熔断器是否打开,如果打开的话就进入降级处理。
  • 如果熔断器是关闭的话,再看是否超资源限制,如果超了的话进入降级处理。
  • 如果没有超过资源限制,则进入调用执行阶段。
  • 如果调用返回错误,或者超时的话,进入降级处理,如果调用成功,则返回结果。

熔断器状态计算

开启熔断器条件

  • 由于依赖服务内部逻辑错误、数据库错误、服务器故障等原因,导致调用返回错误,且请求错误率或者错误次数达到一定阀值。
  • 由于网络延迟、网络波动或者死锁等原因,导致调用超时,且重试一定次数后依然不能成功。
  • 当队列满或者协程数达到阀值后。

补充

在依赖方处理请求前,我们有两种处理方式:

  • 为依赖的每个微服务安排一个队列,让请求先进入队列排队,每个队列安排一个线程池来处理里面的请求,如果队列长度超过阀值,说明请求处理不过来了,这时进入降级处理。
  • 如果你使用的是Golang语言,可以不用队列,直接给每个请求安排一个协程来处理,当并发的协程数超过阀值时,进入降级处理。

熔断粒度

熔断器粒度是在微服务级别呢?还是API接口级别?

我们知道熔断是发生在微服务之间的,当A服务的依赖B服务发生故障时,我们应该把A服务和B服务切断。请大家思考下这种场景:

B服务的其中一个API接口发生故障,而其他接口能正常工作。这种场景下也要把A服务和B服务整个切断吗?

我们看看下图,对比下:
微服务-API网关-熔断降级_第1张图片
服务A依赖服务B,而服务B依赖服务C、服务D、服务E,/api3这个接口需要调用服务E。

按照图中所示,如果服务E发生故障,那么熔断器会把服务A和服务B完全隔离,这可能会造成服务A的整个瘫痪,这不是我们想要的。在实际工作中,特定API接口发生故障的概率是比较高的,比如我们在单元测试中对某个接口的测试不充分,导致某个接口很容易报错。所以熔断粒度最好能细到API接口级别,这样的系统架构更健壮。所以最好的方案是把把熔断细粒度到API级别。如下图所示。
微服务-API网关-熔断降级_第2张图片

数据库选型

熔断器生成的数据主要有以下几个方面:

  • 依赖服务和被依赖服务以及API接口之间的关系
  • API接口级别的熔断器状态
  • 熔断机制相关的阀值、超时时间、间隔时间等

这是很典型的树形结构,可以采用Etcd、Zookeeper、Consul等分布式数据库。树形结构如图:
微服务-API网关-熔断降级_第3张图片

降级机制

当熔断开启后,为了保证网关/集群整体的可用性,我们需要提供一种退路(fallback)机制,比如从缓存中取上一次的结果,或者返回空值等等。

此外如果有多种退路,可以设计多级退路机制,当第一种退路机制失败后,再尝试第二种退路机制,以此类推。

熔断器状态设计

请大家思考下,熔断器应该有几种状态?开启关闭这两种状态我们是知道的,还有没有其他状态?

问题思考

在发现了某个微服务有故障后,我们开启了熔断器,过了一段时间,有故障的服务被修复了,那我们怎么让熔断器知道要关闭呢?

问题解决

我们可以在熔断器开启后,每隔一段时间放行一个请求,如果请求调用成功,我们就关闭熔断器;如果调用失败,我们再关闭,循环往复下去。

根据上面的分析,我们可以得出熔断器应该有三个状态:关闭开启半开启。熔断器默认是关闭状态,当触发熔断后状态变更为开启,在等待到指定的时间,再放行一个请求检测服务是否正常,这期间熔断器会变为半开启状态,熔断探测服务可用则继续变更为关闭,关闭熔断器。

微服务-API网关-熔断降级_第4张图片

你可能感兴趣的:(微服务,API网关,微服务,熔断,降级)