icon-cookie
The website uses cookies to optimize your user experience. Using this website grants us the permission to collect certain information essential to the provision of our services to you, but you may change the cookie settings within your browser any time you wish. Learn more
I agree
blank_error__heading
blank_error__body
Text direction?

【Dalston】【第四章】容错保护(Hystrix)

我们在实践微服务架构时,通常会将业务拆分成一个个微服务,微服务之间通过网络进行通信,进行互相调用,造成了微服务之间存在依赖关系。我们知道由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟甚至调用失败,而调用失败又会造成用户刷新页面并再次尝试调用,再加上其它服务调用,从而增加了服务器的负载,导致服务瘫痪,最终甚至会导致整个服务“雪崩”。

Netflix为解决这个问题根据断路器模式创建了一个名为Hystrix的库。“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

HystrixFallback

当然,在请求失败频率较低的情况下,Hystrix还是会直接把故障返回给客户端。只有当失败次数达到阈值(默认在20秒内失败5次)时,断路器打开并且不进行后续通信,而是直接返回备选(FallBack)响应。

1. 示例代码

对于上一篇我们提到了Feign默认是整合了Ribbon和Hystrix这两个框架,所以代码我们在上一篇的基础上进行修改。

首先,需要说明的是实现微服务容错保护的是服务消费方,也就是Mall工程。那接下来我们代码的更改也主要都是对Mall工程进行修改,其它工程的代码将保持不变。

1.1 增加对Hystrix的依赖

在pom文件中增加如下代码:

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

1.2 开启Hystrix的支持

修改Application类:

package com.product;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableCircuitBreaker//启用断路由功能
@EnableFeignClients/*(basePackages = "com.product.**")*///开启Feign相关功能,打成jar包时必须指定包的路径
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

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

}

这里增加了@EnableCircuitBreaker注解,也就是启用断路器支持

1.3 实现ProductService的FallBack

这里我们新增了一个实现类,并实现了ProductService接口:

package com.product.service.impl;

import java.util.Collections;
import java.util.List;

import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;

import com.product.entity.Product;
import com.product.service.ProductService;

@Component
public class ProductServiceFallBack implements ProductService{

    @Override
    public List<Product> list() {
        return Collections.emptyList();
    }

    @Override
    public Product detail(@PathVariable("itemCode") String itemCode) {
        return new Product("error", "未知", "TwoStepsFromJava-Fallback", 0);
    }
    
}

对于list方法,我们直接返回了一个空白集合(当前,你可以在这里定义任何你想返回给用户显示的信息)。detail方法则返回了一个固定产品信息。

1.3 让ProductService具有容错能力

这个很简单,我们只需要在注解中进行配置即可,如下:

package com.product.service;

import org.springframework.cloud.netflix.feign.FeignClient;

import com.product.api.ProductApiService;
import com.product.service.impl.ProductServiceFallBack;

@FeignClient(name = "PRODUCT-SERVICE", fallback = ProductServiceFallBack.class)
public interface ProductService extends ProductApiService{

}

这个仅仅是在@FeignClient注解中增加了fallback的配置,并设置其值为我们刚刚新建的类:ProductServiceFallback

1.4 让Feign启用Hystrix

这个需要在application.properties中增加下面一个配置:

feign.hystrix.enabled=true

1.5 容错测试

1.首先,我们启动Server、client及consumer,启动后在Server的监控界面可以看到注册的服务如下:

2.我们在浏览器中访问:http://localhost:8080/prod/1,我们可以看到如下界面,说明我们的服务调用是成功的。

3.我们停掉client服务,这时候在Server的监控界面可以看到注册的服务如下,说明service服务已经宕机,此时我们再访问上面的地址依然可以得到正确的响应。

4.此时我们再访问上面的地址,将会看到如下界面:

 

可以看到FallBack已经启作用,当全部service不起作用时,mall-web中的ProductService进入了回退处理。

1.6 在不使用Feign时如何使用Hystrix

其实Hystrix提供了两个对象来支持回退处理:HystrixCommandHystrixObservableCommand,其中后者是用在依赖的服务返回多个操作结果的时候,这里我们只演示一下HystrixCommand的使用,对于后者可自行尝试,或者查看官方文档

这里假设我们有一个UserController其中findById方法需要进行容错保护,那么代码如下:

@HystrixCommand(fallbackMethod="findByIdFallback")
@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
public User findById(@PathVariable Long id) {
    return this.restTemplate.getForObject("http://USER-SERVICE/"+ id, User.class);
}

public User findByIdFallback(Long id) {
    User user = new User();
    user.setId(-1);
    user.setName("-default-");
    return user;
}

可以看出,对于FallBack方法只需要与原方法具有相同的参数及返回值即可,也就是说函数签名要相同。当然@HystrixCommand注解还有很多属性可以自定义,大家可以自行进行尝试。

2. Hystrix容错原理简析

  • 请求封装: 不论是HystrixCommand还是HystrixObervableCommand从类命名上可以看到Hystrix其实是使用了"命令模式",通过命令模式实现对服务调用操作的封装,将每个命令在一个独立线程中进行执行;
  • 跳闸机制: 当某个服务的错误率超过一定阀值时(默认在20秒内失败5次), Hystrix可以自动或手动进行服务跳闸,停止向该服务请求一段时间;
  • 资源隔离: Hystrix为每一个服务依赖都维护了一个小型线程池,如果该线程池已满,那么发往该服务的请求就会立即被拒绝,而不是排队等候,从而加速服务失败的判定;
  • 服务监控: Hystrix可以近乎实时地监控运行指标和配置的变化,例如对请求的成功、失败、超时以及拒绝等;
  • 回退机制: 当请求失败、超时、被拒绝、或当断路器打开时,执行相应的回退逻辑;
  • 自我修复: 当断路器打开一段时间后,Hystrix会进入"半开"状态,断路器会允许一个请求尝试对服务进行请求,如果该服务可以调用成功,则关闭断路器,否则将继续保持断路器打开。

3. Hystrix监控

Hystrix除了实现服务容错之外,还提供了对服务请求的监控:每秒执行的请求数、成功数等。开启Hystrix的监控非常简单,一个是添加spring-cloud-starter-hystrix,这个在之前的示例中以及添加。二是添加spring-boot-starter-actuator,能够让/hystrix-stream端点可以获取到Hystrix的监控数据。

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

启动服务后,我们在浏览器中输入: http://localhost:8800/hystrix.stream就会看到下面的界面:

可以看到页面会重复输出一些统计数据(注: 你要先尝试访问一下所提供的服务才会有这些数据输出)。至于这些数据到底是什么我在这里就不一一解析了,幸好Hystrix还为我们提供了一个可视化界面来查看这些数据。

3.1 Hystrix Dashboard

当然你可以为Hystrix Dashboard新建一个工程(最好也是),我这里为了简化,直接将Dashboard集成到consumer工程中。

首先,我们在pom.xml中增加下面的依赖:

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

然后,在主启动类中增加@EnableHystrixDashboard注解,开启Hystrix Dashboard服务,如:

package com.product;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@EnableHystrixDashboard
@EnableCircuitBreaker//启用断路由功能
@EnableFeignClients/*(basePackages = "com.product.**")*///开启Feign相关功能,打成jar包时必须指定包的路径
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

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

}

最后,重启consumer工程即可。

我们在浏览器中输入: http://localhost:8800/hystrix,可以看到如下界面:

说明Dashboard已经启动成功。然后在界面中输入之前的地址: http://localhost:8800/hystrix.stream,然后点击[Monitor Stream]就可以看到统计报表页面:

从截图中可以看到有两个服务接口的统计数据:list和detail

每个方法的统计信息中包含两个重要的图形信息:一个实心圆和一个曲线。

  • 实心圆:包含两个含义。颜色表示实例的健康程度,健康程度从绿色、黄色、橙色、红色递减。大小则根据请求流量的大小发生变化,流量越大则实心圆越大,反之则小。
  • 曲线: 统计了2分钟内的请求流量的变化,通过该曲线可以对流量进行上升和下降的趋势分析。

对于界面中的数字,其表示的意义如下:

 
Hystrix-090

在Dashboard首页时,我们知道Hystrix Dashboard支持三种监控方式:

  • 默认集群监控: 通过http://turbine-hostname:port/turbine.stream开启,实现对默认集群的监控;
  • 指定集群监控: 通过http://turbine-hostname:port/turbine.stream?cluster=[clusterName]开启,实现对指定clusterName集群的监控;
  • 单机应用监控: 通过http://hystrix-app:port/hystrix.stream开启,实现对某个服务实例的监控。

在上面的示例中我们演示的第三种方式,至于如何继承Turbine实现对集群的监控,我们将在后续篇幅中进行讲解。

原文地址:http://www.jianshu.com/p/57906ee8d506

Measure
Measure
Related Notes
Get a free MyMarkup account to save this article and view it later on any device.
Create account

End User License Agreement

Summary | 6 Annotations
@EnableCircuitBreaker//启用断路由功能
2018/06/21 15:26
这里增加了@EnableCircuitBreaker注解,也就是启用断路器支持
2018/06/21 15:26
fallback = ProductServiceFallBack.class
2018/06/21 15:28
这个仅仅是在@FeignClient注解中增加了fallback的配置,并设置其值为我们刚刚新建的类:ProductServiceFallback。
2018/06/21 15:28
增加@EnableHystrixDashboard注解,开启Hystrix Dashboard服务
2018/06/21 15:34
@EnableHystrixDashboard
2018/06/21 15:35