Hystrix-超时机制和断路器模式

一 超时机制、断路器模式简介

1.1 背景

Hystrix-超时机制和断路器模式_第1张图片

假设服务提供者响应非常缓慢,那么消费者对提供者的请求线程就会被等待,知道服务返回,在高并发高负载的场景下,如果不做任何处理,这种问题很有可能造成所有处理用户请求的线程的资源耗竭,而不能响应用户进一步请求。

如果服务消费者又是另外服务的提供者,那么有可能产生级联反应,导致其它的下一级服务消费者不可用,最终产生雪崩效应。

 

1.2 解决方案

1.2.1 超时机制

通过网络请求其他服务时,都设置超时。正常情况下,一个远程调用,即使毫秒就返回了。

当依赖的服务不可用的时候,或者因为网络问题,响应时间会变得很长(几十秒)。而通常情况下,一次远程调用对应了一个线程或者进程,如果响应太慢,那这个线程、进程就会得不到释放。而线程和进程是系统资源,如果大量线程、进程都不被释放,越积越多,服务资源就会被耗尽。所以我们必须设置超时请求。

 

1.2.2 断路器模式

类似于电短路的时候,跳闸。电流量过大,就会自动断开电路,避免电路升温,烧断电路或者电器。

当依赖的服务有大量超时的时候,再让新的请求去访问已经没有太大意义,只会无谓的消耗现有资源。譬如我们设置了超时时间为1秒,如果短时间有大量请求在1秒内得不到响应,往往意味着异常。此时就没有必要让更多的请求去访问这个依赖了,我们应该使用断路器避免资源浪费。

断路器可以实现快速失败,如果在一段时间内侦测到许多的类似的错误,就会强迫其以后的多个调用快速失败,不再请求所依赖的服务,从而防止应用程序不断的尝试执行可能失败的操作,这样应用程序可以继续执行而不用等待修正错误。断路器模式也可以使得应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。

断路器模式就类似于那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生几次错误,然后决定使用允许操作继续,否则直接返回错误。

 

 

 

二 Hystrix传播Security Context或者SpringScope

如果你想将本地线程上下文传播到注解HystrixCommand中,默认的声明是不会起到这个作用的,因为它是在一个线程中启动的。你可以选择让Hystrix使用同一个线程,通过一些配置或直接写在注解上,通过使用isolation strategy属性。

比如:

@HystrixCommand(fallbackMethod ="stubMyService",

   commandProperties = {

     @HystrixProperty(name="execution.isolation.strategy",value="SEMAPHORE")

    }

)

同样的方式适用于如果你用@SessionScope 或者 @RequestScope。你应该知道什么时候去做这件事因为有些运行时异常报找不到scoped上下文。

 

你也可以选择设置hystrix.shareSecurityContext 属性为true。这样做会自动配置一个Hystrix 并发策略插件钩子,然后会将SecurityContext从你当前主线程

传输到一个使用Hystrix Command注解的地方。

 

 

三 Hysteria Health Indicator 及Metric System

3.1health indicator 健康指标

断路器的状态同样暴露在/health端点上。

{

   "hystrix": {

       "openCircuitBreakers": [

           "StoreIntegration::getStoresByLocationLink"

        ],

       "status": "CIRCUIT_OPEN"

    },

   "status": "UP"

}

3.2Hystrix Metrics Stream

使用Hystrix metricsstream需要引入依赖spring-boot-starter-actuator。这会暴露/hystrix.stream作为一个管理端点。

   org.springframework.boot

   spring-boot-starter-actuator

四 Feign对Hystrix的支持

我们上面所说的熔断机制都是基于在方法上添加@HystrixCommand注解,然后通过属性fallbackMethod实现回退的。然而Feign是以接口形式工作的,他没有方法体,那么前面所述的方式是否依然适合Feign呢?

那么Feign要如何整合Hystrix呢?而且要如何实现Feign的回退呢?

Spring Cloud默认已经为Feign整合了Hystrix,只要Hystrix在项目的classpath中,Feign默认就会用断路器包裹的所有方法。

4.1 为Feign添加回退

首先添加fallback属性为FeignClient,并且指定一个class,这个class实现了接口

@FeignClient(name="microservice-provider-user",configuration=Configuration1.class,

fallback=HystrixClientFallback.class)

public interface UserFeignClient {

 

      @RequestLine("GET /user/{id}")

      public User findById(@Param("id") Long id);

}

 

创建实现了Feign接口的类,并且实现fallback方法:

@Component

public class HystrixClientFallbackimplements UserFeignClient {

 

      @Override

      public UserfindById(Long id) {

           User user = new User();

           user.setId(-1L);

           user.setName("默认用户");

           return user;

      }

}

4.2 禁用单个FeignClient对Hystrix的支持

4.2.1 如果是某些Feign客户端想禁用Hystrix

@FeignClient(name="microservice-provider-user",configuration=Configuration1.class,

fallback=HystrixClientFallback.class)

public interface UserFeignClient {

 

      @RequestLine("GET /user/{id}")

      public User findById(@Param("id") Long id);

}

@Configuration

public class Configuration1 {

      @Bean

      @Scope("prototype")

      public Feign.BuilderfeignBuilder() {

           return Feign.builder();

      }

}

 

4.2.2 如果是希望全局禁用

在application.yml中添加feign.hystrix.enabled=false即可

 

4.3 Feign使用fallbackFactory的属性打印fallback异常

如果有时候我们需要知道发生了什么异常,或者造成回退的原因是什么,我们应该怎么做呢?

我们可以在FeignClient注解上属性加上fallbackFactory属性

首先,创建一个类

public classHystrixClientFallbackFactory

      implementsFallbackFactory{

 

      private static final Logger logger = LoggerFactory.getLogger

           (HystrixClientFallbackFactory.class);

      @Override

      public UserFeignClientcreate(Throwable cause) {

           /**

            * ----日志最好放在各个fallback方法中,而不要直接放在create方法中

            * ----否则在启动的时候,就会打印日志

            */

           return new UserFeignClient(){

                 @Override

                 public UserfindById(Long id) {

                      HystrixClientFallbackFactory.logger.info

                            ("fallback,causedby: "+cause);

                      User user = new User();

                      user.setId(-1L);

                      user.setName("默认用户");

                      return user;

                 }

           };

      }

}

然后:在Feign客户端的注解@FeignClient上加上属性

fallbackFactory

@FeignClient(name="microservice-provider-user",configuration=Configuration1.class,

      fallbackFactory=HystrixClientFallbackFactory.class)

public interface UserFeignClient {

 

      @RequestLine("GET /user/{id}")

      public User findById(@Param("id") Long id);

}

 

Fallbackfactory属性还有其他用途, 我们可以让不同的异常返回不同的回退结果,从而使得Feign的回退更加灵活。例如:

public classHystrixClientFallbackFactory

      implementsFallbackFactory{

 

      private static final Logger logger = LoggerFactory.getLogger

           (HystrixClientFallbackFactory.class);

      @Override

      public UserFeignClientcreate(Throwable cause) {

           /**

            * ----日志最好放在各个fallback方法中,而不要直接放在create方法中

            * ----否则在启动的时候,就会打印日志

            */

           return new UserFeignClient(){

                 @Override

                 public UserfindById(Long id) {

                      HystrixClientFallbackFactory.logger.info

                            ("fallback,causedby: "+cause);

                      User user = new User();

                      if (cause instanceof IllegalArgumentException) {

                            user.setId(-1L);

                      } else {

                            user.setId(-2L);

                      }

                      user.setName("默认用户");

                      return user;

                 }

           };

      }

}

五Hystrix的监控

5.1 指标化监控

处理实现容错外,Hystrix还提供了近乎实时的监控。HystrixCommand和HystrixObservableCommand在执行时,会生成执行结果和运行指标,比如每秒执行的请求数,成功数等,这些监控数据在对分析应用时很有用。

Spring-cloud-starter-hystrix已包含该模块,在此基础上,只需为项目添加spring-boot-starter-actuator,就可以使用/hystrix.stream端点获得Hystrix的监控信息了。

然后就可以访问了/hystrix.stream

 

对于Feign项目的Hystrix监控,我们需要在启动类上加上@Enable-

CircuitBreaker,这样就可以使用/hystrix.stream

 

5.2 可视化监控(HystrixDashboard)

前面的方式我们很难通过肉眼迅速看出当前系统运行状态,因为是以文字演示的,使用Hystrix 仪表盘,我们一眼就可以看出当前的运行状态,让监控数据可视化,图形化。

首先:添加依赖

           <dependency>

                 <groupId>org.springframework.cloudgroupId>

                 <artifactId>spring-cloud-starter-hystrix-dashboardartifactId>

           dependency>

其次: 在启动类上添加@EnableHystrixDashboard,我么修改端口为8030

@SpringBootApplication

@EnableHystrixDashboard

public classMovieServiceHystrixDashBoardRunner {

      @Bean

      @LoadBalanced

      public RestTemplaterestTemplate(){

           return new RestTemplate();

      }

 

      public static void main(String[] args) {

           SpringApplication.run(MovieServiceHystrixDashBoardRunner.class, args);

      }

}

server:

  port: 8030

最后:这样一个简单的Hystrix Board就完成了,我们知道,我们并没有把Hystrix Dashboard注册到Eureka Server上,访问localhost:8030/

Hystrix

Hystrix-超时机制和断路器模式_第2张图片

六 Turbine

前面我们已经知道,/hystrix.stream端点用于监控单个微服务实例,但是微服务架构体系中一般会包含若干个微服务,在生产环境中每一个微服务都可能会集群部署的,监控单个实例的话,就需要在Hystrix Dashboard上切换想要监控的地址,这显示是很不方便的,怎么办呢?

6.1Turbine简介

Turbine是一个聚合Hystrix监控数据的工具,他可以将相关/hystrix.stream端点的数据聚合到一个组合的/turbine.stream中,从而让集群监控的更加方便。

Hystrix-超时机制和断路器模式_第3张图片

6.2 使用turbine监控多个微服务

# 添加依赖

<dependency>

      <groupId>org.springframework.cloudgroupId>

      <artifactId>spring-cloud-starter-hystrixartifactId>

dependency>

<dependency>

      <groupId>org.springframework.cloudgroupId>

      <artifactId>spring-cloud-starter-turbineartifactId>

dependency>

# 启动类添加注解@EnableTurbine

@SpringBootApplication

@EnableTurbine

public classTurbineHystrixApplication {

      public static void main(String[] args) {

           SpringApplication.run(TurbineHystrixApplication.class, args);

      }

}

# 修改application.yml配置文件

Hystrix-超时机制和断路器模式_第4张图片

turbine.aggregator.clusterConfig: 集群名字,多个逗号分割

turbine.appConfig: 微服务名称,多个逗号分割

# 访问

localhost:8031/turbine.stream?cluster=MICROSERVICE-CONSUMER-FEIGN-WITH-HYSTRIX

或者

localhost:8031/turbine.stream?cluster=MICROSERVICE-CONSUMER-RIBBON-WITH-HYSTRIX

 

如果启动了 Hystrix Dashboard,那么可以在Dashboard可视化展示数据

 


你可能感兴趣的:(微服务/spring,cloud)