SpringCloud(8)Hystrix的使用

0.什么是Hystrix

Hystrix是一个用于处理分布式系统中的延迟容错的开源库,在分布式系统中,很多依赖会不可避免的出现调用失败的情况,如超时、异常等,Hystrix可以保证一个依赖出现问题的时候,不会导致整体的服务出错,避免了级联故障,避免出现链式影响,提高分布式系统的弹性

“断路器”本身是一个开关装置,当某个服务单元出现故障后,通过断路器的故障监控(类似熔断保险丝),来向调用方返回一个备选的可处理的响应(FallBack),而不是去长时间的等待,或者是返回一个调用方无法处理的异常,这样能够保证调用方服务不会长时间的等待,不必要的占用,避免了异常错误在系统中的蔓延,乃至雪崩

1.Hystrix三个重要概念

1.服务降级

服务忙请稍后再试,不让客户端等待,直接返回一个有好的提示,Fallback

什么情况下会发生服务降级?

  1. 程序运行异常
  2. 超时
  3. 服务熔断触发服务降级
  4. 线程池打满触发

2.服务熔断

类似保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级方法返回友好提示

3.服务限流

秒杀等高并发业务,严禁一窝蜂地过来拥挤,限制一次过N个,进行排队,有序进行

2.Hystrix项目构建

①新建一个提供者项目,并导入web所需依赖以及hystrix和eureka的依赖

Hystrix的依赖如下

 <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>

然后新建一个服务类以及一个controller用于测试,各有一个正常方法和一个带有休眠3秒的模拟超时的方法。
service类:

@Service
public class PaymentService {
    
    

    public String paymentOk(String serverPort){
    
    
        return "Server Port:"+serverPort+",is OK";
    }

    public String paymentTimeout(String serverPort){
    
    
        try {
    
    
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "Server Port:"+serverPort+",is Timeout";
    }
}

controller类:

@RestController
@Slf4j
@RequestMapping("/payment")
public class PaymentController {
    
    


    @Value("${server.port}")
    private String serverPort;

    @Autowired
    private PaymentService paymentService;

    /** 正常 */
    @GetMapping("/hystrix/ok")
    public String paymentOk(){
    
    
        return paymentService.paymentOk(serverPort);
    }

    /** 测试超时 */
    @GetMapping("/hystrix/timeout")
    public String paymentTimeout(){
    
    
        return paymentService.paymentTimeout(serverPort);
    }
}

这时候开启项目,进行测试没有任何问题。接下来使用jmeter进行压力测试。直接设置200*100次请求,这个时候自己再去浏览器进行访问ok方法,发现ok方法也开始卡顿,接下来加入消费者进行远程调用。

在这里插入图片描述
②创建消费者项目,并导入eureka、feign、hystrix

eureka等配置跟之前一样,然后创建feign的接口类和控制器类进行测试。

Feign的接口类:

@Component
@FeignClient(value = "CLOUD-PAYMENT-HYSTRIX-SERVICE")
public interface FeignService {
    
    

    @GetMapping("/payment/hystrix/ok")
    public String paymentOk();

    @GetMapping("/payment/hystrix/timeout")
    public String paymentTimeout();
}

controller类:

@RestController
@Slf4j
@RequestMapping("/consumer/payment")
public class OrderController {
    
    

    /** 注入feign接口 */
    @Autowired
    FeignService feignService;

    @GetMapping("/hystrix/ok")
    public String orderOk(){
    
    
        return feignService.paymentOk();
    }

    /** 超时控制 */
    @GetMapping("/hystrix/timeout")
    public String orderTimeout(){
    
    
        return feignService.paymentTimeout();
    }
}

首先正常测试,ok方法一切正常,秒回,当jmeter对提供者的服务进行高并发测试时,消费者远程调用时也非常慢,并且有可能会出现超时的错误。

③解决这些问题

问题1. 超时导致服务器变慢

超时不在一直等待,必须有服务降级,返回一个可处理的响应。

问题2.出错(宕机或应用程序出错)

提供者出错,消费者端不能一直等待,必须有服务降级,有兜底

3.使用服务降级

①提供者服务加入fallback

在提供者的服务上对所需要服务降级的服务加上@HystrixCommand注解,并指定fallbackMethod属性为自己设置的用于回调的一个应急方法,并指定commandProperties属性,这个属性是包括@HystrixProperty注解的数组,用于指定服务降级所需要的条件。

payment_fallback方法就是用于出现异常出错的情况,来返回的备用方法,这里的条件设置的是超时2s

@Service
public class PaymentService {
    
    

    public String paymentOk(String serverPort){
    
    
        return "Server Port:"+serverPort+",is OK";
    }

    @HystrixCommand(fallbackMethod = "payment_fallback",commandProperties = {
    
    
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String paymentTimeout(String serverPort){
    
    
        try {
    
    
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "Server Port:"+serverPort+",is Timeout";
    }

    public String payment_fallback(String serverPort){
    
    
        return "Server Port:"+serverPort+",is FALLBACK_METHOD..........";
    }
}

然后需要在主启动类上加入@EnableCircuitBreaker注解,开启断路器。

接下来,开启项目,先直接访问这个提供者的方法,进行测试,先不在消费者端测试。超时后,自动给返回了设置的fallback方法,服务降级测试成功。

在这里插入图片描述

接下来进行测试如果是运行时出现异常,能否触发服务降级?

首先注释掉sleep休眠语句,然后加入一个会导致运行时异常的语句。
在这里插入图片描述
接下来开启项目进行测试。

可以看到,出现运行时异常后,直接触发了服务降级。
在这里插入图片描述

②在消费者端加入fallback

一般来说服务降级是在消费者客户端进行设置的,所以接下来在消费者进行配置。

首先需要在主启动类加入@EnableHystrix注解,开启Hystrix服务,然后在controller类使用@HystrixCommand注解进行配置服务降级。

controller类:

/** 超时控制 */
    @GetMapping("/hystrix/timeout")
    @HystrixCommand(fallbackMethod = "orderFallback",commandProperties = {
    
    
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String orderTimeout(){
    
    
        return feignService.paymentTimeout();
    }

    public String orderFallback(){
    
    
        return "服务繁忙或出现错误,请稍后再试";
    }

然后开启项目进行测试,可以看到超时后的确触发了服务降级,返回了fallback方法内容。

在这里插入图片描述
但是,将服务提供端的服务休眠时间改成1.5s后,发现没到设置的2s超时,仍旧触发了服务降级,推测是因为,hystrix默认的全局超时时间是1s,然后自己设置的是2s,会自动选择时间短的,也就是1s的超时时间,所以需要在yml配置文件中,修改默认的超时时间,下面修改为3s,这样就会使用自己设置的2s。

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

设置完成后,发送请求,发现的确等待了2s
在这里插入图片描述
③配置全局的服务降级

使用@DefaultProperties注解,加到需要配置的类上,就会给这个类下的加入了@HystrixCommand注解但是没指定特别的fallback的方法开启默认的全局配置的服务降级,指定DefaultFallback属性为全局的fallback方法。

@RestController
@Slf4j
@RequestMapping("/consumer/payment")
@DefaultProperties(defaultFallback = "globalFallback")
public class OrderController {
    
    

    /** 注入feign接口 */
    @Autowired
    FeignService feignService;

    @GetMapping("/hystrix/ok")
    @HystrixCommand
    public String orderOk(){
    
    
        int g=1/0;
        return feignService.paymentOk();
    }

    /** 超时控制 */
    @GetMapping("/hystrix/timeout")
    @HystrixCommand(fallbackMethod = "orderFallback",commandProperties = {
    
    
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String orderTimeout(){
    
    
        return feignService.paymentTimeout();
    }

    public String orderFallback(){
    
    
        return "服务繁忙或出现错误,请稍后再试";
    }

    public String globalFallback(){
    
    
        return "全局配置的服务降级生效!";
    }
}

在ok方法上加入@HystrixCommand注解,但是不配置具体属性,然后加入一个导致运行时异常,然后开启项目,进行测试。可以看到,全局配置的fallback被返回了回来。

在这里插入图片描述
④对Feign的接口类服务降级

对项目中已有的FeignService这个Feign的接口类,创建一个类(FeignFallbackService)实现该接口,这个类统一的对接口中的方法进行异常处理,并在接口的@FeignClient注解上配置Fallback属性为该实现类。

Feign的接口类:

@Component
@FeignClient(value = "CLOUD-PAYMENT-HYSTRIX-SERVICE",fallback = FeignFallbackService.class)
public interface FeignService {
    
    

    @GetMapping("/payment/hystrix/ok")
    public String paymentOk();

    @GetMapping("/payment/hystrix/timeout")
    public String paymentTimeout();
}

实现了Feign的接口类的Fallback类:

@Component
public class FeignFallbackService implements FeignService {
    
    
    @Override
    public String paymentOk() {
    
    
        return "------------paymentOK method Fallback-----------";
    }

    @Override
    public String paymentTimeout() {
    
    
        return "------------paymentTimeout method Fallback-----------";
    }
}

然后在yml文件中,开启feign对hystrix的支持

feign:
  hystrix:
    enabled: true

进行测试,直接将服务提供者8011关闭掉,模拟宕机的情况,然后再次调用接口测试,可以看到的确使用了实现类中的对应的方法实现作为fallback方法。

在这里插入图片描述

4.服务熔断

什么是服务熔断?

服务熔断是为了应对雪崩效应的一个保护机制,当扇出链路的某一个微服务出现错误或者等待时间过长,会进行服务降级,进而熔断该节点微服务的调用,快速返回错误信息,防止整个链路连锁崩溃。当检测到该节点正常后,会恢复链路

①在提供者服务添加触发熔断的方法

提供者的服务类:

详细的配置解释请看HystrixCommand配置信息

@HystrixCommand(fallbackMethod = "paymentBreaker_fallback",commandProperties = {
    
    
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//开启熔断器,默认为true
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//开启熔断器所需要的最小请求
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),//错误请求的百分比,超过这个百分比才能开启
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000")//检查是否可用的间隔
    })
    public String paymentBreaker(@PathVariable("id") Integer id){
    
    
        if (id<0){
    
    
            throw new RuntimeException("id不能小于0");
        }
        return "paymentBreaker成功,id:"+id;
    }

    public String paymentBreaker_fallback(@PathVariable("id") Integer id){
    
    
        return "id不能小于0,id:"+id;
    }

提供者的controller类:

调用breaker服务进行测试

@GetMapping("/hystrix/breaker/{id}")
    public String paymentBreaker(@PathVariable Integer id){
    
    
        return paymentService.paymentBreaker(id);
    }

接下来开启项目,直接访问提供者的接口进行测试。

设置的是最少10次请求,所以快速的访问10次,每次都抛出异常。
在这里插入图片描述
10次之后,开启了熔断器这时候,就算传个大于0的值,依旧会快速失败,返回fallback方法。
在这里插入图片描述
过几秒后,熔断器进行检测,发现服务正常,再次进行调用,可以看到,熔断器已经关闭,服务正常,这就是熔断器的自动恢复。
在这里插入图片描述

②熔断器的三个重要参数

  1. 快照时间窗:熔断器是否打开需要统计请求和错误的数据,统计的时间范围就是快照时间窗,默认为最近10秒
  2. 请求总数阈值:在快照时间窗内,请求数至少要满足请求总数阈值,才能打开熔断器,例如:设置为20,在10秒内有19个请求,而且全部错误,一样不会打开熔断器
  3. 错误百分比阈值:当请求总数在快照时间窗内,错误的请求满足了请求总数的设定的百分比,则打开熔断器,例如:有30个请求,已经超过了请求总数阈值,然后其中15个错误请求,错误百分比阈值设置的是50%,则此时就会打开熔断器

5.图形化Dashboard的搭建

①新建一个项目,并导入相关依赖。

首先需要导入springboot web相关的依赖,然后导入Hystrix的dashboard依赖,dashboard依赖如下:

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

然后配置项目端口为9001,并在yml配置文件加入以下配置:

hystrix:
  dashboard:
    proxy-stream-allow-list: "*"

接着在主启动类上加入@EnableHystrixDashboard注解

@SpringBootApplication
@EnableHystrixDashboard
public class CloudConsumerHystrixDashboard9001Application {
    
    

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

然后开启项目,输入网址localhost:9001/hystrix进入图形化界面。
在这里插入图片描述
需要注意的是需要被监控的项目,一定要有actuator的依赖。

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

②配置需要被监控的服务

在提供者服务的主启动类中,配置监控的默认地址为/hystrix.stream,代码如下

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableCircuitBreaker
public class CloudProviderHystrixPayment8011Application {
    
    

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

    @Bean
    public ServletRegistrationBean getServlet(){
    
    
        HystrixMetricsStreamServlet hystrix=new HystrixMetricsStreamServlet();
        ServletRegistrationBean bean=new ServletRegistrationBean(hystrix);
        bean.setLoadOnStartup(1);
        bean.addUrlMappings("/hystrix.stream");
        bean.setName("HystrixMetricsStreamServlet");
        return bean;
    }
}

然后开启提供者服务,打开Dashboard,然后输入 项目地址/hystrix.stream,如下所示
在这里插入图片描述
然后点击监控
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41120971/article/details/108030680
今日推荐