一、前言

1、为什么需要断路器

在分布式架构中,一个应用依赖多个服务是非常常见的,如果其中一个依赖由于延迟过高发生阻塞,调用该依赖服务的线程就会阻塞,如果相关业务的QPS较高,就可能产生大量阻塞,从而导致该应用/服务由于服务器资源被耗尽而拖垮。

另外,故障也会在应用之间传递,如果故障服务的上游依赖较多,可能会引起服务的雪崩效应。就跟数据瘫痪,会引起依赖该数据库的应用瘫痪是一样的道理。

所以,为了应对以上问题,就需要有支持服务隔离、熔断等操作的工具

2、什么是Hystrix?

Hystrix是SOA/微服务架构中提供服务隔离、熔断、降级机制的工具/框架。通过以上手段来降低服务故障带来的关联影响,以提高系统的整体可用性。

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable. -https://github.com/Netflix/Hystrix

Hystrix工作原理:https://ken.io/note/netflix-hystrix-intro-principle

3、本篇环境信息
框架 版本
Spring Boot 2.0.0.RELEASE
Spring Cloud Finchley.BUILD-SNAPSHOT
JDK 1.8.x
4、准备工作
  • 准备Eureka Server、服务提供者

参考上一篇 https://ken.io/note/spring-cloud-feign-quickstart
源码:https://github.com/ken-io/springcloud-course/tree/master/chapter-03/

启动Eureka Server: http://localhost:8800
启动Test Service:http://localhost:8602

  • 了解服务消费者

服务消费者Ribbon: https://ken.io/note/spring-cloud-ribbon-quickstart
服务消费者Feign:
https://ken.io/note/spring-cloud-feign-quickstart

二、Ribbon + Hystrix应用

本篇基于 https://ken.io/note/spring-cloud-ribbon-quickstart
中ribbonclient项目代码进行修改,引入Spring Cloud Netflix Hystrix

源码:https://github.com/ken-io/springcloud-course/tree/master/chapter-02/ribbonclient

  • 修改pom.xml,引入Spring Cloud Netflix Hystrix
  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  </dependency>
@EnableHystrix
@EnableDiscoveryClient
@SpringBootApplication
public class App {

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • 修改TestService.java,增加熔断功能
  1. 在index方法上增加注解 ==@HystrixCommand==并通过fallbackMethod参数指定熔断后执行的方法
  2. 定义熔断方法,返回熔断后的提示
@Service
public class TestService {

    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "indexError")
    public Object index() {
        return restTemplate.getForObject("http://testservice", String.class);
    }

    public Object plus(int numA, int numB) {
        String url = String.format("http://testservice/plus?numA=%s&numB=%s", numA, numB);
        return restTemplate.getForObject(url, String.class);
    }

    public Object indexError() {
        return "{\"code\": 999,\"message\": \"熔断\"}";
    }
}

启动 ribbonclient 项目

访问:http://localhost:8604/ti ,将看到

{
  "code": 0,
  "message": "hello",
  "content": null,
  "serviceName": "testservice",
  "host": "localhost:8602"
}

关闭testservice,然后再访问 http://localhost:8604/ti ,将看到

{
  "code": 999,
  "message": "熔断"
}

这就说明,当testservice不可用的时候,我们访问增加了Hystrix容错措施的接口,会触发快速失败,立即执行fallback。而不是一直等待直到超时,很大程度上降低了造成阻塞可能。

三、Feign + Hystrix应用

本篇基于 https://ken.io/note/spring-cloud-feign-quickstart
中feignclient项目代码进行修改
源码:https://github.com/ken-io/springcloud-course/tree/master/chapter-03/feignclient

Feign已经引入了Hystrix,所以不需要再单独引入

  • 修改application.yml,开启Hystrix
feign:
  hystrix:
    enabled: true
  • 新建 TestServiceHystrix.java

TestServiceHystrix会作为TestService的熔断实现

package io.ken.springcloud.feignclient.service;

import io.ken.springcloud.feignclient.model.Plus;
import io.ken.springcloud.feignclient.model.Result;
import org.springframework.stereotype.Component;

@Component
public class TestServiceHystrix implements TestService {

    @Override
    public String indexService() {
        return "{\"code\": 999,\"message\": \"熔断\"}";
    }

    @Override
    public Result plusService(int numA, int numB) {
        Result result = new Result();
        result.setCode(999);
        result.setMessage("熔断");
        return new Result();
    }

    @Override
    public Result plusabService(Plus plus) {
        Result result = new Result();
        result.setCode(999);
        result.setMessage("熔断");
        return new Result();
    }

    @Override
    public Result plus2Service(Plus plus) {
        Result result = new Result();
        result.setCode(999);
        result.setMessage("熔断");
        return new Result();
    }
}
  • 修改TestService,指定fallback类
@FeignClient(value = "testservice", fallback = TestServiceHystrix.class)
public interface TestService {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    String indexService();

    @RequestMapping(value = "/plus", method = RequestMethod.GET)
    Result plusService(@RequestParam(name = "numA") int numA, @RequestParam(name = "numB") int numB);

    @RequestMapping(value = "/plus", method = RequestMethod.POST, consumes = "application/json")
    Result plusabService(Plus plus);

    @RequestMapping(value = "/plus2", method = RequestMethod.POST)
    Result plus2Service(@RequestBody Plus plus);


}

启动 feignclient 项目

访问:http://localhost:8605/ti ,将看到

{
  "code": 0,
  "message": "hello",
  "content": null,
  "serviceName": "testservice",
  "host": "localhost:8602"
}

关闭testservice,然后再访问 http://localhost:8605/ti ,将看到

{
  "code": 999,
  "message": "熔断"
}

这就说明,当testservice不可用的时候,我们访问增加了Hystrix容错措施的接口,会触发快速失败,立即执行fallback。而不是一直等待直到超时,很大程度上降低了造成阻塞可能。

四、备注

  • 本篇代码示例

https://github.com/ken-io/springcloud-course/tree/master/chapter-04

  • 本篇参考

https://github.com/Netflix/Hystrix/wiki

  • 延伸阅读

https://ken.io/note/netflix-hystrix-intro-principle