Spring Cloud 学习笔记06----断路器(Hystrix)(Finchley版本)

简介

接上一篇Spring Cloud 学习笔记04----服务消费者(RestTemplate+Ribbon(客户端负载均衡)),接下来我们来学习另外一个组件 断路器(Hystrix)。
在微服务架构中,我们将系统拆分成很多个独立服务单元,服务与服务之间通过RPC的方式调用,在Spring Cloud 中可以通过RestTemplate+Ribbon 或者Feign 的方式调用。为了保证高可用性,单个服务通常会集群部署。这样就有可能因为网络原因或者是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后等待出现故障的依赖方响应形成任务积压,最终导致自身服务的瘫痪。

断路器(Hystrix)简介

Netflix的创造了一个调用的库Hystrix实现了断路器图案。在微服务架构中,通常有多层服务调用。
如图所示,微服务图

微服务图
较低级别的服务中的服务故障可能导致用户级联故障。当对特定服务的调用的不可用达到一个阀值时(Hystrix中的默认值为5秒内的20次故障),断路器打开,向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
如下图. Hystrix回退防止级联故障

在这里插入图片描述

快速入门

在使用Spring Cloud Hystrix 实现断路器之前。首先,我们先构建一个服务调用关系。
我们以上一篇的项目为基础,首先启动如下项目:
eureka-server 工程:服务注册中心,端口1111
order-provider 工程: order-service的服务,两个实例启动端口分别是8081 和8082
service-ribbon 工程:使用Ribbon实现的服务消费者,端口为8764。
在未加入断路器之前,关闭8081的实例,发送GET请求到http://localhost:8764/getOrderService,可以看到如下输出
在这里插入图片描述

引入Hystrix。

  1. 在service-ribbon 工程的pom.xml 引入 spring-cloud-starter-hystrix 依赖
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>
  1. 在service-ribbon 工程的主类ServiceRibbonApplication中使用@EnableCircuitBreaker注解开启断路器功能:
@SpringBootApplication
@EnableEurekaClient    //ribbon
@EnableCircuitBreaker  //断路器
@SpringCloudApplication
public class ServiceRibbonApplication {

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

	@Bean
	@LoadBalanced  //开启负载均衡
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

PS: 这里可以使用Spring Cloud应用中的@SpringCloudApplication注解来修饰应用主类,该注解的具体定义如下所示。可以看到,该注解中包含了上述我们所引用的三个注解, 这也意味着一个Spring Cloud 标准应用包含服务发现以及断路器。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
  1. 改造服务消费方式,在HelloService 类中,在getOrderService方法上增加@HystrixCommand注解。代码如下:
  @HystrixCommand(fallbackMethod ="helloFallback" )
    public String getOrderService() {
        return restTemplate.getForObject("http://ORDER-SERVICE/dc",String.class);
    }

    public String helloFallback() {
        return "服务出现故障了";
    }

下面,我们来验证一下断路器实现的服务回调逻辑,重新启动之前关闭的8081端口order-provider,确保此时服务注册中心,两个order-provider以及service-ribbon均已启动,访问http://localhost:8764/getOrderService 可以轮询到两个order-provider 并返回一些文字信息。当轮询到8081时,输出内容服务出现故障了,不再是之前的错误内容,Hystrix的服务回调生效。
在这里插入图片描述
除了通过断开具体的服务实例来模拟某个节点无法访问的情况之外,我们还可以模拟一下服务阻塞的情况,我们对order-provider中增加/hello接口,具体如下:

    @GetMapping("/hello")
    public String hello(HttpServletRequest request) throws InterruptedException {
//        让处理线程等待几分钟
        int sleepTime = new Random().nextInt(3000);
        Thread.sleep(sleepTime);
        String services = "Services: " + discoveryClient.getServices() + ";port=" + request.getServerPort();
        System.out.println(services);

        return "hello world";
    }

通过Thread.sleep()方法可以让/hello接口的处理线程不是马上返回内容,而是在阻塞几秒之后才返回内容。由于Hystrix默认超时时间为2000毫秒,所以这里采取0至3000的随机数以让处理过程有一定概率发生超时来触发断路器。测试如下:
在这里插入图片描述
在这里插入图片描述

源码地址

https://github.com/XWxiaowei/SpringCloud-Learning/tree/master/2-Finchley版教程示例/Chapter5-1

参考

【Spring Cloud 微服务实战 第5章】




作者:码农飞哥

微信公众号:码农飞哥