详解Spring Cloud 熔断机制--断路器

断路器(Curcuit Breaker)模式

在分布式环境下,特别是微服务结构的分布式系统中, 一个软件系统调用另外一个远程系统是非常普遍的。这种远程调用的被调用方可能是另外一个进程,或者是跨网路的另外一台主机, 这种远程的调用和进程的内部调用最大的区别是,远程调用可能会失败,或者挂起而没有任何回应,直到超时。更坏的情况是, 如果有多个调用者对同一个挂起的服务进行调用,那么就很有可能的是一个服务的超时等待迅速蔓延到整个分布式系统,引起连锁反应, 从而消耗掉整个分布式系统大量资源。最终可能导致系统瘫痪。

断路器(Circuit Breaker)模式就是为了防止在分布式系统中出现这种瀑布似的连锁反应导致的灾难。

一旦某个电器出问题,为了防止灾难,电路的保险丝就会熔断。断路器类似于电路的保险丝, 实现思路非常简单,可以将需要保护的远程服务嗲用封装起来,在内部监听失败次数, 一旦失败次数达到某阀值后,所有后续对该服务的调用,断路器截获后都直接返回错误到调用方,而不会继续调用已经出问题的服务, 从而达到保护调用方的目的, 整个系统也就不会出现因为超时而产生的瀑布式连锁反应。

1. 基本模式

上图是断路器(Curcuit Breaker)的结构,它有两个基本状态(close和open)和一个基本trip动作:

close状态下, client向supplier发起的服务请求, 直接无阻碍通过断路器, supplier的返回值接直接由断路器交回给client.

open状态下,client向supplier发起的服务请求后,断路器不会将请求转到supplier, 而是直接返回client, client和supplier之间的通路是断的

trip: 在close状态下,如果supplier持续超时报错, 达到规定的阀值后,断路器就发生trip, 之后断路器状态就会从close进入open.

2. 扩展模式

基本的断路器模式下,保证了断路器在open状态时,保护supplier不会被调用, 但我们还需要额外的措施可以在supplier恢复服务后,可以重置断路器。一种可行的办法是断路器定期探测supplier的服务是否恢复, 一但恢复, 就将状态设置成close。断路器进行重试时的状态为半开(half-open)状态。

3. 断路器的使用场合:

一个supplier一般很稳定,如果一旦故障发生后, 检查和恢复需要的时间比较长,通常无法短时间内快速修复的,那么这种服务比较适合采用断路器模式。否则很可能导致ping-pong效应。

3. 断路器不适合的场合:

为了防止一个应用程序试图调用一个远程服务或访问共享资源,如果​​该操作是极有可能失败, 这种模式可能不适合。

对于处理中的应用程序访问本地专用资源,例如在存储器内数据结构。在这种环境下通常也不适合,使用断路器只会增加系统开销。

下面直接介绍Spring Cloud的断路器如何使用。

SpringCloud Netflix实现了断路器库的名字叫Hystrix. 在微服务架构下,通常会有多个层次的服务调用.下面是微服架构下, 浏览器端通过API访问后台微服务的一个示意图:

一个微服务的超时失败可能导致瀑布式连锁反映,下图中,Hystrix通过自主反馈实现的断路器,防止了这种情况发生。

图中的服务B因为某些原因失败,变得不可用,所有对服务B的调用都会超时。当对B的调用失败达到一个特定的阀值(5秒之内发生20次失败是Hystrix定义的缺省值), 链路就会被处于open状态, 之后所有所有对服务B的调用都不会被执行, 取而代之的是由断路器提供的一个表示链路open的Fallback消息. Hystrix提供了相应机制,可以让开发者定义这个Fallbak消息.

open的链路阻断了瀑布式错误, 可以让被淹没或者错误的服务有时间进行修复。这个fallback可以是另外一个Hystrix保护的调用, 静态数据,或者合法的空值. Fallbacks可以组成链式结构,所以,最底层调用其它业务服务的第一个Fallback返回静态数据.

下面,进入正题,在之前的两HELLO WORLD服务集群中加入断路器, 防止其中一个Hello world挂掉后, 导致系统发生连锁超时失败。

1. 在maven工程(前面章节中介绍的Ribbon或者Feign工程)的pom.xml中添加hystrix库支持断路器

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

2.在Ribbon应用中使用断路器

1). 在Spring Boot启动类上添加@EnableCircuitBreaker注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ServiceRibbonApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServiceRibbonApplication.class, args);
  }

2). 用@HystrixCommand注解标注访问服务的方法

@Service
public class HelloService {
  @Autowired RestTemplate restTemplate;

  @HystrixCommand(fallbackMethod = "serviceFailure")
  public String getHelloContent() {
    return restTemplate.getForObject("http://SERVICE-HELLOWORLD/",String.class);
  }

  public String serviceFailure() {
    return "hello world service is not available !";
  }
}

@HystrixCommand注解定义了一个断路器,它封装了getHelloContant()方法, 当它访问的SERVICE-HELLOWORLD失败达到阀值后,将不会再调用SERVICE-HELLOWORLD, 取而代之的是返回由fallbackMethod定义的方法serviceFailure()。@HystrixCommand注解定义的fallbackMethod方法,需要特别注意的有两点:

第一, fallbackMethod的返回值和参数类型需要和被@HystrixCommand注解的方法完全一致。否则会在运行时抛出异常。比如本例中,serviceFailure()的返回值和getHelloContant()方法的返回值都是String。

第二, 当底层服务失败后,fallbackMethod替换的不是整个被@HystrixCommand注解的方法(本例中的getHelloContant), 替换的只是通过restTemplate去访问的具体服务。可以从中的system输出看到, 即使失败,控制台输出里面依然会有“call SERVICE-HELLOWORLD”。

启动eureka服务,只启动两个Helloworld服务,然后中断其中一个(模拟其中一个微服务挂起),访问http://localhost:8901/然后刷新, 由于有负载均衡可以看到以下两个页面交替出现。可以看到第二个被挂起的服务,被定义在Ribbon应该里面的错误处理方法替换了。

4. 在Feign应用中使用断路器

1). Feign内部已经支持了断路器,所以不需要想Ribbon方式一样,在Spring Boot启动类上加额外注解

2). 用@FeignClient注解添加fallback类, 该类必须实现@FeignClient修饰的接口。

@FeignClient(name = "SERVICE-HELLOWORLD", fallback = HelloWorldServiceFailure.class)
 public interface HelloWorldService {
   @RequestMapping(value = "/", method = RequestMethod.GET)
   public String sayHello();
 }

3). 创建HelloWorldServiceFailure类, 必须实现被@FeignClient修饰的HelloWorldService接口。注意添加@Component或者@Service注解,在Spring容器中生成一个Bean

@Component
public class HelloWorldServiceFailure implements HelloWorldService {
  @Override
  public String sayHello() {
    System.out.println("hello world service is not available !");
    return "hello world service is not available !";
  }
}

4). Spring Cloud之前的Brixton版本中,Feign是缺省是自动激活了断路器的,但最近的Dalston版本已经将缺省配置修改为禁止。

原因参见: https://github.com/spring-cloud/spring-cloud-netflix/issues/1277, 这一点要注意。所以要在Feign中使用断路器, 必须在application.yml中添加如下配置:

feign:
  hystrix:
   enabled: true

5). 启动Feign应用, 访问http://localhost:8902/hello, 可以一看到和Ribbon一样的效果。

参考:http://projects.spring.io/spring-cloud/spring-cloud.html#_circuit_breaker_hystrix_clients

http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign-hystrix

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • 详解SpringCloud微服务架构之Hystrix断路器
(0)

相关推荐

  • 详解SpringCloud微服务架构之Hystrix断路器

    一:什么是Hystrix 在分布式环境中,许多服务依赖项中的一些将不可避免地失败.Hystrix是一个库,通过添加延迟容差和容错逻辑来帮助您控制这些分布式服务之间的交互.Hystrix通过隔离服务之间的访问点,停止其间的级联故障以及提供回退选项,从而提高系统的整体弹性. Hystrix旨在执行以下操作 1:对通过第三方客户端库访问(通常通过网络)的依赖关系提供保护并控制延迟和故障. 2:隔离复杂分布式系统中的级联故障. 3:快速发现故障,尽快恢复. 4:回退,尽可能优雅地降级. 5:启用近实时监

  • 详解Spring Cloud 熔断机制--断路器

    断路器(Curcuit Breaker)模式 在分布式环境下,特别是微服务结构的分布式系统中, 一个软件系统调用另外一个远程系统是非常普遍的.这种远程调用的被调用方可能是另外一个进程,或者是跨网路的另外一台主机, 这种远程的调用和进程的内部调用最大的区别是,远程调用可能会失败,或者挂起而没有任何回应,直到超时.更坏的情况是, 如果有多个调用者对同一个挂起的服务进行调用,那么就很有可能的是一个服务的超时等待迅速蔓延到整个分布式系统,引起连锁反应, 从而消耗掉整个分布式系统大量资源.最终可能导致系统

  • 详解Spring Cloud Feign 熔断配置的一些小坑

    1.在使用feign做服务调用时,使用继承的方式调用服务,加入Hystrix的熔断处理fallback配置时,会报错,已解决. 2.使用feign默认配置,熔断不生效,已解决. 最近在做微服务的学习,发现在使用feign做服务调用时,使用继承的方式调用服务,加入Hystrix的熔断处理fallback配置时,会报错,代码如下: @RequestMapping("/demo/api") public interface HelloApi { @GetMapping("user/

  • 详解spring cloud整合Swagger2构建RESTful服务的APIs

    前言 在前面的博客中,我们将服务注册到了Eureka上,可以从Eureka的UI界面中,看到有哪些服务已经注册到了Eureka Server上,但是,如果我们想查看当前服务提供了哪些RESTful接口方法的话,就无从获取了,传统的方法是梳理一篇服务的接口文档来供开发人员之间来进行交流,这种情况下,很多时候,会造成文档和代码的不一致性,比如说代码改了,但是接口文档没有改等问题,而Swagger2则给我们提供了一套完美的解决方案,下面,我们来看看Swagger2是如何来解决问题的. 一.引入Swag

  • 详解Spring Cloud Zuul网关修改为短连接方法

    目录 一.问题分析 二.解决方式 一.问题分析 之前在用zuul网关的时候,请求几次然后连接就断开了.原因是因为http1.1之后,默认走的都是connection=keep-alive 长连接.但没有心跳维持,顾1分钟断开一次.但RestFul一般都是走短连接就行了.因此想着只要修改头部connection属性就行了. 就是在过滤器中修改Zuul的RequestContext ctx对象 //设置请求为短连接 ctx.addZuulRequestHeader("connection"

  • 详解Spring的核心机制依赖注入

    详解Spring的核心机制依赖注入 对于一般的Java项目,他们都或多或少有一种依赖型的关系,也就是由一些互相协作的对象构成的.Spring把这种互相协作的关系称为依赖关系.如A组件调用B组件的方法,可称A组件依赖于B组件,依赖注入让Spring的Bean以配置文件组织在一起,而不是以硬编码的方式耦合在一起 一.理解依赖注入 依赖注入(Dependency Injection) = 控制反转(Inversion ofControl,IoC):当某个Java实例(调用者)需另一个Java实例(被调

  • 详解spring cloud config实现datasource的热部署

    关于spring cloud config的基本使用,前面的博客中已经说过了,如果不了解的话,请先看以前的博客 spring cloud config整合gitlab搭建分布式的配置中心 spring cloud config分布式配置中心的高可用 今天,我们的重点是如何实现数据源的热部署. 1.在客户端配置数据源 @RefreshScope @Configuration// 配置数据源 public class DataSourceConfigure { @Bean @RefreshScope

  • 详解spring cloud config整合gitlab搭建分布式的配置中心

    在前面的博客中,我们都是将配置文件放在各自的服务中,但是这样做有一个缺点,一旦配置修改了,那么我们就必须停机,然后修改配置文件后再进行上线,服务少的话,这样做还无可厚非,但是如果是成百上千的服务了,这个时候,就需要用到分布式的配置管理了.而spring cloud config正是用来解决这个问题而生的.下面就结合gitlab来实现分布式配置中心的搭建.spring cloud config配置中心由server端和client端组成, 前提:在gitlab中的工程下新建一个配置文件config

  • 详解spring cloud构建微服务架构的网关(API GateWay)

    前言 在我们前面的博客中讲到,当服务A需要调用服务B的时候,只需要从Eureka中获取B服务的注册实例,然后使用Feign来调用B的服务,使用Ribbon来实现负载均衡,但是,当我们同时向客户端暴漏多个服务的时候,客户端怎么调用我们暴漏的服务了,如果我们还想加入安全认证,权限控制,过滤器以及动态路由等特性了,那么就需要使用Zuul来实现API GateWay了,下面,我们先来看下Zuul怎么使用. 一.加入Zuul的依赖 <dependency> <groupId>org.spri

  • 详解spring cloud使用Hystrix实现单个方法的fallback

    本文介绍了spring cloud-使用Hystrix实现单个方法的fallback,分享给大家,具体如下: 一.加入Hystrix依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> 二.编写Controller package c

  • 详解Spring Cloud 跨服务数据聚合框架

    AG-Merge Spring Cloud 跨服务数据聚合框架 解决问题 解决Spring Cloud服务拆分后分页数据的属性或单个对象的属性拆分之痛, 支持对静态数据属性(数据字典).动态主键数据进行自动注入和转化, 其中聚合的静态数据会进行 一级混存 (guava). 举个栗子: 两个服务,A服务的某张表用到了B服务的某张表的值,我们在对A服务那张表查询的时候,把B服务某张表的值聚合在A服务的那次查询过程中 示例 具体示例代码可以看 ace-merge-demo 模块 |------- ac

随机推荐