使用Hystrix实现容错

  Spring Cloud 集成Hystrix来提供容错的能力,从而实现微服务的容错

  容错主要方式

  假设服务提供者的响应很慢,那么消费者的请求将会被强制等待,直到响应或者超时。 在高负载的情况下,很有可能发生的情况是,当依赖的服务不可用,自身的服务也被拖垮,这就是雪崩效应,当服务提供者不可用导致消费者不可用,并将不可用逐渐放大的过程。

  容错的主要手段:

  为网络请求设置超时: 通常情况下一次远程调用对应一个线程,如果响应太慢,这个线程就得不到释放,而线程占用的资源当然也不会被释放,当高并发或者未处理完的线程越来越多,资源终将被耗尽。

  使用断路器模式:如果有对某个微服务的请求存在大量超时,禁止访问该微服务,防止雪崩。 当该微服务可用,断路器可以自动诊断是否已经恢复,恢复访问请求,从而实现微服务的自我修复,从而提升应用的高可用性。

  Hystrix是一个实现超时机制和断路器模式的工具类库, 由Netfix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统可用性与容错性。

  机制:

  当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open).这时所有请求会直接失败而不会发送到后端服务.

  断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN).

  Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量,并且断路器有自我检测并恢复的能力.

     

  1、包裹请求:使用HystrixCommand / HystrixObservableCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行

  2、跳闸机制:当某服务的错误率超过一定阀值时,Hystrix可以自动或者手动跳闸,停止请求该服务一段时间
  3、资源隔离:Hystrix为每个依赖都维护一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判断
  4、监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
  5、回退机制:相当于服务降级,当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑可由开发人员自行提供,例如返回一个缺省值
  6、自我修复:断路器打开一段时间后,会自动进入“半开”状态

  因为熔断是发生在调用方即消费者,消费者的工程添加依赖:

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

  启动类增加@EnableCircuitBreaker或者@EnableHystrix注解

package com.smile;

@SpringBootApplication
@EnableCircuitBreaker
public class ConsumerMovieRibbonHystrixApplication {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

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

}

  控制层

package com.smile.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.smile.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class MovieController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    LoadBalancerClient loadBalancerClient;

    @HystrixCommand(fallbackMethod = "findByIdDefault",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000"),
            @HystrixProperty(name="metrics.rollingStats.timeInMilliseconds",value="10000")
    },threadPoolProperties ={
            @HystrixProperty(name="coreSize",value="1"),
            @HystrixProperty(name="maxQueueSize",value = "10")
    })
    @GetMapping("/movie/{id}")
    public User findId(@PathVariable Long id){
        // 调用注册在Eureka上的服务端的地址
        return restTemplate.getForObject("http://provider-user/user/"+id,User.class);
    }

    /**
     * @param id
     * @return
     * @desc 当请求失败、超时、被拒绝,或当断路器打开时,执行的逻辑
     */
    public User findByIdDefault(Long id) {
        User user = new User();
        user.setId(id);
        user.setUsername("默认用户");
        return user;
    }
}

    上述Controller层的方法中,看到在findById方法上增加了注解 @HystrixCommand(fallbackMethod = “findByIdDefault”),通过fallbackMethod 属性指定当请求失败、超时、被拒绝,或当断路器打开时,执行的方法findByIdDefault

  feign使用Hystrix

  开启Hystrix

server:
  port: 7891

spring:
  application:
    name: consumer-movie-feign-hystrix
#eureka
eureka:
  client:
    service-url:
      defaultZone: http://Jim:land123@localhost:8761/eureka
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}

# Disable HystrixCommands For FeignClients By Default
feign:
  hystrix:
    enabled: true

  修改Feign接口

  使用fallback属性指定回退类

package com.smile.feignclient;

@FeignClient(value = "provider-user",fallback = FeignClientCallback.class)
public interface UserFeignClient {
    @RequestMapping(method= RequestMethod.GET,value="/user/{id}")
    User findUserById(@PathVariable("id") Long id);
}

  回退类 也需要实现上面的接口,同时需要标注@Component让其成为受spring管理的bean

package com.smile.feignclient;

import com.smile.model.User;
import org.springframework.stereotype.Component;

@Component
public class FeignClientCallback implements UserFeignClient{

    @Override
    public User findUserById(Long id) {
        User user = new User();
        user.setId(id);
        user.setUsername("默认用户");
        return user;
    }
}

  测试

  1. 启动microservice-discovery-eureka,注册中心
  2. 启动micorservice-provider-user,服务提供者
  3. 启动micorservice-consumer-movie-feign-hystrix,服务消费者开启了Hystrix

 Hystrix监控

   Hystrix除了提供容错外,还提供功能近乎实时的监控。HystrixCommand和HystrixObservableCommand在执行时,会生成执行结果和运行指标。

   Hystrix的hystrix-metrics-event-stream模块 将监控信息以text/event-stream的格式暴露给外部系统。添加 spring-cloud-starter-netflix-hystrix依赖后,看下pom的依赖关系,如下图,可以知道 spring-cloud-starter-netflix-hystrix已经包含该模块。

      只需要添加spring-boot-starter-actuator即可,就可以使用 /actuator/hystrix.stream端点来获取Hystrix的监控信息

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

    application.yml 中 配置信息开启所有的监控端点

#actuator  启用所有的监控端点 “*”号代表启用所有的监控端点,可以单独启用,例如,health,info,metrics
#  spring boot 升为 2.0 后,为了安全,默认 Actuator 只暴露2个端点,heath 和 info,继续
# 访问  http://localhost:7890/actuator/metrics
management:
  endpoints:
     web:
       exposure:
         include: "*"
  endpoint:
      health:
        show-details: always

  测试

  1、启动discovery-eureka,注册中心

  2、启动provider-user,服务提供者
  3、启动consumer-movie-ribbon-hystrix,服务消费者,整合了Hystrix , 端口 7902
  4、访问 http://localhost:7902/actuator/hystrix.stream ,如下
  

  一直处于ping 请求状态,是因为consumer-movie-ribbon-hystrix中注解了@HystrixCommand的方法还未被执行,没有产生监控数据,请求变产生数据

  为系统会不断的刷新以便可以获取实时的监控数据,包括HystrixCommand的名称、group名称、断路器名称、错误率、错误数等

  

  Feign项目整合Hystrix监控

  Hystrix的hystrix-metrics-event-stream模块 将监控信息以text/event-stream的格式暴露给外部系统。

  1、添加 spring-cloud-starter-netflix-hystrix

       2、启动类增加@EnableCircuitBreaker或者@EnableHystrix注解

       3、引入spring-boot-starter-actuator并开启端点

     spring-boot-starter-actuator是必不可少的,application.yml中开启端点

  Hystrix Dashboard

  打算注册到Eureka上,所以也需要添加spring-cloud-starter-netflix-eureka-client

      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

  启动类增加注解@EnableHystrixDashboard

  打算注册到Eureka上,所以也需要添加@EnableDiscoveryClient注解

package com.smile;

@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrixDashboard
public class HystrixDashboardApplication {

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

}

  配置文件application.yml

server:
  port: 7892

spring:
  application:
    name: micorservice-hystrix-dashboard

#eureka
eureka:
  client:
    service-url:
      defaultZone: http://Jim:land123@localhost:8761/eureka
  instance:
    prefer-ip-address: true  # 起码点击后 会看到ip信息
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}

  注册到Eureka上,所以需要先启动microservice-discovery-eureka,然后再启动该服务,启动成功后,访问http://localhost:7892/hystrix

  

    分别输入url和自定义的title

  访问下 http://localhost:7901/movie/1 触发hystrix收集信息,多访问几次,信息如下

  通过Dashboard 对单个节点的微服务进行近乎实时的可视化监控

  

  

      参考:

  https://www.jianshu.com/p/c29d35331256
  

posted on 2019-05-11 23:40  溪水静幽  阅读(335)  评论(0)    收藏  举报