飞道的博客

Spring CLoud以Eureke为注册中心的服务搭建(六)---Hystrix断路器

525人阅读  评论(0)

Hystrix简介

​ Hystrix是一个用于处理分布式系统的延迟和容错的开源库。在分布式系统中服务与服务的依赖中,总会出现失败的情况,如:Feign写的超时、异常、服务停止等等。

​ Hystrix能够保证在一个依赖出现问题的时候,不让导致整个服务的级联故障,以提高分布系统的弹性。通过断路器监控,给调用方返回一个预设的响应(Fallback)而不是直接报错。它会保证调用方的线程不会长时间占用,避免整个服务瘫痪。

Hystrix主要有3个部分
  • 服务降级 如:返回自定义的提示,服务忙等可读性提示 Fallback 降级条件:程序异常、超时或者主动触发
  • 服务熔断 如:服务器承受最大访问后,直接拒绝访问,调用降级方法返回可读性提示。 服务降级–>熔断–>恢复调用
  • 服务限流 如:高并发等操作,禁止请求量过大拥挤,设定一个阈值,排队有序进行

代码演示

接着前面四篇文章,现在有4个服务:注册中心7000、消费者8001、生产者9001、生产者9002

在两个生产者pom中添加Hystrix依赖

				 <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
从生产者实现降级

​ 修改controller,增加service类,具体实现如下

生产者8001修改如下:

package com.cto.cloud.controller;

import com.cto.cloud.service.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 
 * @author Zhang Wei
 * @date 2020/5/23 15:08
 * @version v1.0.1
 */
@RestController
@RequestMapping("/provider")
public class IndexController {

    @Autowired
    private ProviderService providerService;

    @GetMapping(value = "/getData")
    public String getData(){
        return providerService.getDataOk();
    }

    @GetMapping(value = "/getDataError")
    public String getDataError(){
        return providerService.getDataError();
    }
}

添加的service

package com.cto.cloud.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 
 * @author Zhang Wei
 * @date 2020/5/23 22:39
 * @version v1.0.1
 */
@Service
public class ProviderService {

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

    /**
     * 正确返回
     * @return
     */
    public String getDataOk(){
        return port + "\t getDataOk";
    }

    /**
     * 故意异常
     * @return
     */
    @HystrixCommand(fallbackMethod = "getDateErrorFallBack",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String getDataError() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return port + "\t getDataError 等3秒";
    }

    public String getDateErrorFallBack(){
        return "服务超时了,我只等你2秒";
    }
}

启动类添加注解 @EnableCircuitBreaker

生产者8002修改

controller一样,service如下

package com.cto.cloud.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 
 * @author Zhang Wei
 * @date 2020/5/23 22:39
 * @version v1.0.1
 */
@Service
public class ProviderService {

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

    /**
     * 正确返回
     * @return
     */
    public String getDataOk(){
        return port + "\t getDataOk";
    }

    /**
     * 故意异常
     * @return
     */
    @HystrixCommand(fallbackMethod = "getDateErrorFallBack",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String getDataError() {
        int i = 10/0;  //计算异常
        return port + "\t getDataError";
    }

    public String getDateErrorFallBack(){
        return "服务异常啦,待会再试";
    }
}

启动类添加注解 @EnableCircuitBreaker

消费者8001添加请求调用:

controller添加

		@GetMapping(value = "/getDataError")
    public Object getDataError(){
        return providerService.getDataError();
    }

service添加

		@GetMapping("/provider/getDataError")
    String getDataError();

顺序启动注册中心7000、消费者8001、生产者9001、生产者9002

访问http://localhost:8001/consumer/getDataError

9001返回

9002返回

至此,生产者端配置熔断可以看到,超时或者异常都会别拦截。

从消费者实现降级

修改Consumer8001 yml

#服务降级开启
feign:
  hystrix:
    enabled: true

这个默认值默认是false,这里配置为true

修改主启动类,添加注解 @EnableHystrix

添加一个公共的Hystrix统一返回类,实现ProviderService方法

package com.cto.cloud.service;

import org.springframework.stereotype.Component;

/**
 * 
 * @author Zhang Wei
 * @date 2020/5/23 23:57
 * @version v1.0.1
 */
@Component
public class ProviderServiceHystrix implements ProviderService{
    @Override
    public String getData() {
        return "服务异常了";
    }

    @Override
    public String getDataError() {
        return "服务异常了";
    }
}

修改ProviderService 添加fallback

package com.cto.cloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author Zhang Wei
 * @version v1.0.1
 * @date 2020/5/18 20:42
 */
@Component
@FeignClient(value = "CLOUD-PROVIDER",fallback = ProviderServiceHystrix.class)
public interface ProviderService {

    @GetMapping("/provider/getData")
    String getData();

    @GetMapping("/provider/getDataError")
    String getDataError();
}

重启Consumer服务,接着降生产者服务器故意关闭模拟宕机

访问http://localhost:8001/consumer/getDataError

返回了自定义异常

服务熔断

修改生产者Provider 9002service

//服务熔断
    @HystrixCommand(fallbackMethod = "getIdErrorFallBack",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50") //失败率达到多少
    })
    public String getId(Integer id) throws Exception {
        if(id < 0){
            throw new Exception("主动异常");
        }
        return port + "-----" + id;
    }
    public String getIdErrorFallBack(){
        return port + "服务超时了,我只等你2秒";
    }

controller

 @GetMapping(value = "/getId/{id}")
    public Object getId(@PathVariable("id") Integer id) throws Exception {
       return providerService.getId(id);
    }

启动注册中心、启动生产者9001

访问http://localhost:9001/provider/getId/1

访问http://localhost:9001/provider/getId/-1


疯狂的点击id为-1的请求10多次以后,切换ID为1,发现服务依旧会报熔断了,而经过访问几次,失败率下降以后服务恢复正常

服务熔断
熔断类型

​ 1.熔断打开
​ 请求不再进行调用当前服务,内部设置时钟(平均故障处理时间),当打开时长达到所设时钟则进入熔断状态
​ 2.熔断关闭
​ 熔断关闭不会对服务进行熔断
​ 3.熔断半开
​ 部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断

断路器开启或者关闭的条件

​ 当满足一定阀值的时候(默认10秒内超过20个请求次数)
​ 当失败率达到一定的时候(默认10秒内超过50%请求失败)
​ 到达以上阀值,断路器将会开启
​ 当开启的时候,所有请求都不会进行转发
​ 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5

Hystrix的工作流程详见官方文档说明:https://github.com/Netflix/Hystrix/wiki/How-it-Works#Flow

本文是在学习过程中整理,如有错误欢迎各位大佬指正!O(∩_∩)O

Github地址

陆续更新中……


转载:https://blog.csdn.net/zyw562123314/article/details/106309118
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场