在微服务中,我们将系统拆分为很多个服务单元,各单元之间通过服务注册和订阅消费的方式进行相互依赖。但是如果有一些服务出现问题了会怎么样?

比如说有三个服务(ABC),A调用B,B调用C。由于网络延迟或C本身代码有问题导致B迟迟得不到回应,这样B调用C的请求就会被挂起,等待。

在高并发的访问的情况下,这些挂起的线程得不到释放,使后续的请求阻塞,最终导致B也挂掉了。依次类推,A可能也会挂掉,进而使整个系统全部崩溃。

为了解决整个问题,Spring Cloud 使用Hystrix进行服务容错保护,包括断路器、线程隔离等一系列的保护功能,今天我们就来看下如何通过Hystrix实现断路器。

一、什么是Spring Cloud Hystrix?什么是断路器?

Spring Cloud Hystrix是基于Netflix的开源框架Hystrix实现的,其目的是为了通过控制那些访问远程系统、服务和第三方的节点,从而对延迟和故障提供强大的容错能力。

断路器类似于我们家里面强电箱里面用到的漏电断路保护器,当服务单元出现故障(类似于电器发生短路),通过断路器的故障监控功能(类似于保险丝),向调用方返回一个错误响应,避免长时间等待,从而避免故障蔓延到整个系统。

二、没有断路器的情况下,页面展示

还记得我们前面写的spring cloud 入门系列二:使用Eureka 进行服务治理里面的三个服务(eureka/hello-service/hello-consumer)吗?我们基于这个进行实验。

  1. 启动eureka服务注册中心,端口号1111
  2. 启动hello-service服务提供者,这里我们启动两个服务,端口号分别为9090,9091
  3. 启动hello-consumer服务消费者,端口号为9999;这个时候我们多次访问http://localhost:9999/hello-consumer是没有问题的
  4. 将hello-service端口号为9091的服务关掉,再去多次访问http://localhost:9999/hello-consumer,报错了

    PS:这里说明下,为什么要多次访问,是因为我们通过ribbon实现了负载均衡,访问http://localhost:9999/hello-consumer的时候,会轮询访问hello-service的两个服务,当访问到端口号是9091的服务时才报错,访问9090的服务就不会有问题。

三、断路器代码实现

接下来我们看下如何进行代码实现,我们不去修改服务注册中心和服务提供者,只需要修改服务消费者hello-consumer

  1. 修改POM文件,引入Hystrix依赖

    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sam</groupId>
    <artifactId>hello-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.1.RELEASE</version>
    </parent> <properties>
    <javaVersion>1.8</javaVersion>
    </properties> <dependencyManagement>
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Camden.SR6</version>
    <type>pom</type>
    <scope>import</scope>
    </dependency>
    </dependencies> </dependencyManagement> <dependencies>
    <!-- 引入eureka 客户端依赖 -->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <!-- 引入ribbon 依赖 ,用来实现负载均衡,我们这里只是使用先不作其他介绍 -->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
    <!-- 引入hystrix 依赖 ,用来实现服务容错保护-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
    </dependencies>
    </project>
  2. 修改启动类,追加注解@EnableCircuitBreaker,开启断路器
    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableCircuitBreaker
    public class ConsumerApp { //@Bean 应用在方法上,用来将方法返回值设为为bean
    @Bean
    @LoadBalanced //@LoadBalanced实现负载均衡
    public RestTemplate restTemplate() {
    return new RestTemplate();
    } public static void main(String[] args) {
    SpringApplication.run(ConsumerApp.class, args);
    }
    }

    这个时候你会发现,这个启动类加了三个注解,这个是不是很麻烦?没关系,我们可以使用注解@SpringCloudApplication

    @SpringCloudApplication
    public class ConsumerApp { //@Bean 应用在方法上,用来将方法返回值设为为bean
    @Bean
    @LoadBalanced //@LoadBalanced实现负载均衡
    public RestTemplate restTemplate() {
    return new RestTemplate();
    } public static void main(String[] args) {
    SpringApplication.run(ConsumerApp.class, args);
    }
    }

    @SpringCloudApplication = @EnableDiscoveryClient +@SpringBootApplication+@EnableCircuitBreaker,从源码就能看出来:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableCircuitBreaker
    public @interface SpringCloudApplication {
    }
  3. 追加service
    @Service
    public class ConsumerService { @Autowired
    RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "errorMsg")
    public String consumer() {
    // 调用hello-service服务,注意这里用的是服务名,而不是具体的ip+port
    restTemplate.getForObject("http://hello-service/hello", String.class);
    return "hello consumer finish !!!";
    } public String errorMsg() {
    return "error!!!";
    }
    }

    我们把原来controller里面的调用RestTemplate的实现放到service里面,并且通过@HystrixCommand来指定回调方法,当出现错误时调用该方法。

  4. 修改controller
    /**
    *这里不再直接调用restTemplate,
    *而是通过调用service进行实现
    *
    */
    @RestController
    public class ConsumerController { @Autowired
    // RestTemplate restTemplate;
    ConsumerService service; @RequestMapping("/hello-consumer")
    public String helloConsumer() {
    // //调用hello-service服务,注意这里用的是服务名,而不是具体的ip+port
    // restTemplate.getForObject("http://hello-service/hello", String.class);
    return service.consumer();
    }
    }
  5. 测试,多次访问,当报错的时候,会显示如下内容

大功告成!

spring cloud 入门系列四:使用Hystrix 实现断路器进行服务容错保护的更多相关文章

  1. SpringCould-------使用Hystrix 实现断路器进行服务容错保护

    消费: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.or ...

  2. spring cloud 入门系列:总结

    从我第一次接触Spring Cloud到现在已经有3个多月了,当时是在博客园里面注册了账号,并且看到很多文章都在谈论微服务,因此我就去了解了下,最终决定开始学习Spring Cloud.我在一款阅读A ...

  3. spring cloud 入门系列五:使用Feign 实现声明式服务调用

    一.Spring Cloud Feign概念引入通过前面的随笔,我们了解如何通过Spring Cloud ribbon进行负责均衡,如何通过Spring Cloud Hystrix进行服务断路保护,两 ...

  4. spring cloud 入门系列六:使用Zuul 实现API网关服务

    通过前面几次的分享,我们了解了微服务架构的几个核心设施,通过这些组件我们可以搭建简单的微服务架构系统.比如通过Spring Cloud Eureka搭建高可用的服务注册中心并实现服务的注册和发现: 通 ...

  5. Spring Cloud 入门教程(四): 分布式环境下自动发现配置服务

    前一章, 我们的Hello world应用服务,通过配置服务器Config Server获取到了我们配置的hello信息“hello world”. 但自己的配置文件中必须配置config serve ...

  6. Spring Cloud 入门教程(七): 熔断机制 -- 断路器

    对断路器模式不太清楚的话,可以参看另一篇博文:断路器(Curcuit Breaker)模式,下面直接介绍Spring Cloud的断路器如何使用. SpringCloud Netflix实现了断路器库 ...

  7. Spring Cloud 入门系列(一)

    前言 Spring Could作为目前最流行基于Java开发的构建微服务的完整框架.发现目前相关系列教程太少,本文是基于官网教程做的一套翻译. 何为Spring Cloud? Spring Cloud ...

  8. spring cloud 入门系列一:初识spring cloud

    最近看到微服务很火,也是未来的趋势, 所以就去学习下,在dubbo和spring cloud之间我选择了从spring cloud,主要有如下几种原因: dubbo主要专注于微服务中的一个环节--服务 ...

  9. spring cloud 入门系列

    springcloud入门总结转发自:https://www.cnblogs.com/sam-uncle/p/9340390.html 最近看到微服务很火,也是未来的趋势, 所以就去学习下,在dubb ...

随机推荐

  1. HashMap就是这么简单【源码剖析】

    前言 声明,本文用得是jdk1.8 前面已经讲了Collection的总览和剖析List集合以及散列表.Map集合.红黑树的基础了: Collection总览 List集合就这么简单[源码剖析] Ma ...

  2. Django中ORM介绍和字段及其参数

    ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM是通过使用描述 ...

  3. mysql导出与导入

    环境 centos6.5 32位 Mysql 5.7.19 导出 mysqldump用法 导出整个数据库 [root@mini2 mysql]# mysqldump -p123456 --databa ...

  4. Android智能手机上的音频浅析

    手机可以说是现在人日常生活中最离不开的电子设备了.它自诞生以来,从模拟的发展到数字的,从1G发展到目前的4G以及不久将来的5G,从最初的只有唯一的功能(打电话)发展到目前的全功能,从功能机(featu ...

  5. 解决MySQL在修改列时因为外键依赖出错的问题

    因为 favorite_food 中的 person_id 对 person 表中的 person_id 有外键依赖关系,所以在执行 ALTER TABLE person MODIFY person_ ...

  6. echarts版本折线图

    1.效果如下:         绘制折线图,应该算是说echarts中使用最简单也算使用频率最高的一种功能了吧.根据官网列子能找出规律,只是有些属性对于初接触者来说,会有点陌生,不过仔细阅读一下还是不 ...

  7. 谈谈App的混合开发

    一.概念 App混合开发,顾名思义,是一个开发模式,指的是开发一个App一部分功能用native构建一部分功能用html5构建,英文名叫:Hybrid App. 在几年前就已经出现了App混合开发模式 ...

  8. 一日一练-CSS CSS中percentage百分值的使用

    子曰:学好百分值,考试考百分 首先是确定CSS 中的percentage 都可以应用在CSS 中的哪些属性,以及这些属性的值如何进行计算的,参考CSS 参考手册进行统计. 定位(Positioning ...

  9. TensorFlow学习笔记(UTF-8 问题解决 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte)

    我使用VS2013  Python3.5  TensorFlow 1.3  的开发环境 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff ...

  10. [UOJ 41]【清华集训2014】矩阵变换

    Description 给出一个 $N$ 行 $M$ 列的矩阵A, 保证满足以下性质: $M > N$. 矩阵中每个数都是 $[0, N]$ 中的自然数. 每行中, $[1, N]$ 中每个自然 ...