一文教你Spring Cloud微服务如何实现熔断降级?

熔断限流概述

在基于Spring Cloud的微服务架构体系下,按照系统功能边界的不一样划分,原先大而全的系统会被拆分为多个不一样的微服务,而相应的微服务会提供一组功能关联的服务接口,并向系统中的其余微服务提供服务。在正常状况下,各个微服务之间功能上相互解耦,从软件的设计上来说会呈现出一个比较合理的状态,可是从调用链路上来看,这种拆分实际上也是拉长了外部服务请求的调用链路。spring

举个例子,在创业公司的早期,考虑到研发维护成本,系统架构设计很简单,从软件结构上看,就是一个api服务面向app端,一个service端面向后台功能。以用户购物场景举例,虽然这个过程逻辑上会经历商品、下单、支付、物流、库存等复杂逻辑的处理,可是由于这些逻辑都耦合在一个系统中,因此从用户的app到后台服务,服务的调用链路并不算太长。即使在这样的状况下,仍是会存在若是请求量忽然剧增,服务端的业务处理线程池被塞满,整个后台系统的数据库链接资源、缓存资源所有被耗尽,从而致使整个服务不可用的状况。数据库

而随着公司的逐步发展,业务请求量与日剧增,为了提升整个系统的吞吐量及可用性,咱们采用了微服务架构的设计,将原先的系统拆分红了商品、订单、支付、物流、库存等多个微服务,而这些服务之间经过网络进行通讯(以Spring Cloud来讲就是经过咱们前面说到的FeignClient进行服务发现后,以HTTP的方式进行网络调用),造成了一次购物请求,会经历app端调用商品微服务进行浏览,选中商品后由商品中心调用订单中心进行下单,而后订单中心调用支付系统进行付款,付款成功后,订单中心再调用物流中心进行发货,与此同时,物流中心调用库存系统进行库存减小的漫长调用链路。bootstrap

这个流程看起来就有点长了,为了方便你们理解,仍是来张图:api

如上图所示,在系统微服务化后,虽然此时每一个微服务都拥有独立的进程资源、业务线程池以及单独的数据库,总体的系统吞吐量比之前高了不少,而且每一个微服务也都是集群部署。可是由于整个调用的网络链路是很是长的,若是此时发生局部网络或者部分微服服务故障的话,依然可能会致使整个微服务系统的瘫痪。缓存

举个例子,假设此时物流服务发生了宕机,可是前面的微服务都不知道,由于整个链路调用都是同步的,因此此时订单服务调用物流微服务的时候会出现部分线程阻塞直至超时异常,同理调用物流的微服务的订单服务的那个线程也会出现阻塞,假如此时业务请求并发量很是高,由于线程阻塞时间过长,那么很快订单微服务及物流微服务的业务线程数资源就会被耗尽,此时用户App端就会出现不只购物功能没法使用,就连商品浏览也不行了,而此时请求量继续增长,状况就会更加恶化,若是业务线程池使用的是无界队列(线程池请求队列),最终还会致使系统内存溢出,此时系统要想自动恢复可能就比较困难了,糟糕的状况就是服务持续不可用,而最终可能只能采用重启整个系统的高昂成原本临时解决下,而这也还不能最终解决问题,由于重启后状况依然可能会发生(若是并无排查及解决掉物流微服务故障缘由的话)。bash

从上面的例子看,一个微服务的故障竟然能致使整个系统的崩溃,而咱们但愿的状况是若是发现物流微服务持续故障的话,此时订单微服务应该是能够感知到,并根据必定的机制进行容错,即订单微服务在知道物流微服务异常的状况下,就暂时先不要把请求发送到物流微服务了,给物流微服务先限流,而在自身本地逻辑中采起一个默认容错逻辑进行熔断后马上返回App调用端,例如,能够先将须要发送的消息缓存,待物流微服务恢复后再从新发送。这样的话,故障的物流微服务也就不会致使订单服务由于同步调用链路超时过长而出现级联故障了。网络

那么在Spring Cloud微服务设计中如何才能实现这样的机制呢?这里涉及到几个问题:架构

  • 微服务如何定义为故障,熔断的条件是什么?也就是说订单微服务如何肯定物流微服务不可用,从而能够实现熔断操做;
  • 被定义为故障的微服务恢复后如何让熔断方感知?订单微服务什么时候才能够继续正常的调用物流微服务,实现故障恢复;
  • Spring Cloud的代码实现机制是什么样的?

以上这些问题,就是本章要讲述的如何在Spring Cloud微服务设计中实现服务熔断限流的内容了!而这一点对于并发量很是高的状况下,实现微服务的可用性是很重要的一个方面。并发

Spring Cloud中集成Hystrix框架

在Spring Cloud微服务设计中须要经过集成Hystrix框架来实现微服务间的熔断保护机制,Hystrix框架会经过监控微服务之间的调用状况,来决定是否启动熔断保护。那么接下来,就让咱们一块儿来看下如何在Spring Cloud项目中经过集成Hystrix框架来实现熔断机制吧!app

引入依赖 要Spring Cloud中使用Hystrix框架,须要引入Hystrix框架的starter依赖包,以下:

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
 </dependency>
复制代码

经过引入此stater依赖包,咱们就能够基于Spring Boot框架的特性,实现对Hystrix框架的开箱即用了。

注解开启熔断器 在Spring Cloud微服务中启用熔断器,须要在微服务的Application主程序上添加org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker注解,如:

@EnableDiscoveryClient
@EnableCircuitBreaker
@SpringBootApplication
@EnableFeignClients(basePackageClasses = {PaymentClient.class})
@EnableScheduling
public class Goods {

    public static void main(String[] args) {
        SpringApplication.run(Goods.class, args);
    }
}
复制代码

经过这样一个简单的注解配置,此时微服务就开启了基于Hystrix的断路器功能。须要说明的是,在某个微服务中开启断路器,实现的是该微服务对其下游微服务的熔断功能,而不是该微服务对其上游调用的熔断,这一点你们不要混淆了,由于在Spring Cloud的微服务体系下,熔断的实现是基于Hystrix本地库来实现的,本质上是客户端熔断,而不是服务端的熔断。相比较于最近谈论比较多的基于Service Mesh的限流熔断功能而言,基于客户端的熔断从应用的形态上看,是与微服务自己融合在一块儿的,而不是独立的服务。

FeignClient开启Hystrix 在微服务中开启断路器后,并不表示就能够马上使用了,在前面的章节中咱们讲过,在Spring Cloud微服务体系中,微服务之间的通讯交互须要经过使用FeignClient来进行,而默认状况下FeignClient中默认状况下是禁用Hystrix的,因此若是须要在微服务中启用Hystrix的熔断功能,则须要经过配置手动开启Hystrix功能,这样FeignClient客户端在微服务之间进行通信调用时,才能在感知到微服务异常的状况下,将错误指标信息反馈给Hystrix框架,从而Hystrix才能根据自身逻辑对熔断器的状态进行启停(关于Hystrix的具体运行原理,咱们在后面的章节中进行介绍)。

如下是咱们在项目的bootstrap.yml文件中,开启FeignClient对Hystrix支持的配置:

feign:
  hystrix:
    enabled: true
复制代码

实现FeignClient服务降级代码

Spring Cloud中微服务之间的服务调用是基于FeignClient的,在实际的工程实践中,咱们通常会单独将微服务的FeignClient调用端代码进行抽离,并以SDK jar包依赖的形式进行发布。通常状况下,能够每一个微服务都抽离一个FeignClient工程代码,这样更加清晰;若是以为太过于麻烦,也能够把多个不一样微服务的FeignClient客户端代码耦合在一块儿,全部的微服务依赖这一个SDK也能够,只是后期若是微服务的数量比较多,而且维护团队比较分散的话,这样也会致使一个很臃肿的项目出现,维护升级更加麻烦而已,你们能够根据团队的实际状况进行规划。

咱们在前面讲述过基于Spring Cloud的微服务的熔断机制,其实是基于Hystrix框架的客户端熔断机制,也就是说上游微服务在经过FeignClient调用下游微服务的时候,若是感知到下游微服务调用异常须要向上向Hystrix框架反馈异常,若是Hystrix框架计算异常指标达到了阀值就会开启熔断器。而以后FeignClient客户端针对该下游微服务的调用,就须要被Hystrix熔断后回调一个相应的本地降级处理方法,从而实现服务降级。

而FeignClient从代码的角度已经支持了这样的设计,咱们在经过@FeignClient注解编写微服务的客户端调用代码时,就能够经过指定相应的Fallback类来处理服务被熔断后的降级逻辑。下面咱们就以本文举例的项目示例,来编写订单微服务的FeignClient客户端SDK代码:order-client。

代码示例:

@FeignClient(value = "order", configuration = OrderClientConfiguration.class, fallback = OrderClientFallback.class)
public interface OrderClient {

    // 查询购物订单扣费状态(内)
    @RequestMapping(value = "/order/queryOrderCost", method = RequestMethod.GET)
    QeuryOrderCostResVo queryOrderCost(@RequestParam(value = "orderId") String orderId) throws InternalApiException;
}
复制代码

根据订单微服务中的服务接口定义,咱们经过@FeignClient注解定义了一个OrderClient.class类,该类声明了微服务的接口定义,假设这里订单微服务提供了一个订单查询接口(一个微服务通常状况下会有多个服务接口,这里举一个接口只是为了好举例)。

咱们能够看到在@FeignClient注解的属性中,有一个fallback属性,这个属性指定了一个服务降级的配置类OrderClientFallback.class。这样,就能够在该类中实现微服务对应方法的降级逻辑了:

public class OrderClientFallback implements OrderClient {

    @Override
    public OrderCostDetailVo orderCost(String orderId, long userId, String busiId, String orderType, int duration,
            int bikeType, String bikeNo, String countryName, int cityId, int orderCost, String currency, int strategyId,
            String tradeTime) {
        return new OrderCostDetailVo();
    }
}
复制代码

能够看到降级处理类其实是OrderClient的一个实现类,因此在这里每一个微服务的接口都会被强制要求实现相应的熔断降级代码。而具体的降级逻辑,则能够根据服务的具体状况进行编写,如这里是返回一个空的消息对象。

以上模式就是在Spring Cloud中经过FeignClient调用时,在开启Hystrix熔断功能后的基本处理套路了。接下来,咱们经过具体的测试效果,来看下熔断器功能的生效状况:

一、在微服务goods中引入order微服务的FeignClient客户端SDK

<dependency>
        <groupId>com.wudimanong.client</groupId>
        <artifactId>order-client</artifactId>
        <version>1.0.0</version>
</dependency>
复制代码

二、为了观测,咱们须要开启HystrixDashboard

引入HystrixDashboard依赖:

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
复制代码

在应用程序主类中开启HystrixDashboard注解:

@EnableHystrixDashboard
@EnableDiscoveryClient
@EnableCircuitBreaker
@SpringBootApplication
@EnableFeignClients
public class GoodsApplication {

    public static void main(String[] args) {
        SpringApplication.run(GoodsApplication.class, args);
    }
}
复制代码

三、此时经过访问HystrixDashboard控制台就能够看到监控指标信息了

咱们假设goods调用order服务正常状况下Ciruit是close状态的,若是此时断掉order服务,而后多刷几回goods调用请求,此时,咱们就发现关于order服务的熔断开关被打开了。

而后咱们恢复order服务,而后再多刷几回调用接口,就会发现Ciruit就会被关闭了。

经过上面的配置,咱们就基本完成了Spring Cloud项目中关于Hystrix熔断器的配置了。

相关文章
相关标签/搜索