Hystrix断路器

Hystrix断路器的概述

分布式系统面临的问题

 

Hystrix是什么

Hystrix能干啥

1.         服务降级

2.         服务熔断

3.         接近实时的监控

Hystrix官网资料

https://github.com/Netflix/Hystrix/wiki/How-To-Use

Hystrix官宣,停更进维

Hystrix的重要概念

服务降级(fallback),服务熔断(break),服务限流(flowlimit)

在分布式系统中,服务与服务之间依赖错综复杂,一种不可避免的情况就是某些服务将会出现失败。Hystrix是一个用于处理分布式系统的延时和容错的开源库,它提供了服务与服务之间的容错功能,主要体现在延迟容错和容错,从而做到控制分布式系统中的联动故障。Hystrix通过隔离服务的访问点,阻止联动故障,并提供故障的解决方案,从而提高了这个分布式系统的弹性。

服务降级

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

乃至雪崩。

哪些情况会出现降级?

l  程序运行异常

l  超时

l  服务熔断出发服务降级

l  线程池/信号量打满也会导致服务降级

服务熔断

类似保险丝达到最大服务访问后,直接拒接访问。然后调用服务降级的方法并返回友好提示。

就是保险丝。服务的降级-》进而熔断-》恢复调用链路

服务限流

秒杀高并发等操作,严禁一窝峰的过来拥挤,大家排队,一秒钟N个,有序进行

Hystrix案例

Hystrix支付微服务构建

构建工程

1.   新建cloud-provider-hystrix-payment8001工程

2.   添加pom
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fengyangcai.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>
3.   写yml
server:
  port: 8001
spring:
  application:
    name: cloud-provider-hystrix-payment
eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://localhost:7003/eureka
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版本
4.   主启动类
@SpringBootApplication
@EnableEurekaClient
//@EnableDiscoveryClient
//@EnableCircuitBreaker//断路器的注解
public class HystrixPaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixPaymentMain8001.class,args);
    }
}
5.   业务类
Service
@Service
public class PaymentService {
//正常的访问方法
    public String paymentInfo_OK(Integer id){
        return "线程池:"+Thread.currentThread().getName()+"paymentInfo_OK,id: "+id+"/t"+"哈哈";
    }
    //一般Hstrix降级放在客户端,这里放在服务端了只是演示而已。
    /* @HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {
         @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
 })*/
    public String paymentInfo_TimeOut(Integer id){
            int time=1;
           // int a=10/0;
        try {
            TimeUnit.SECONDS.sleep(time);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return "线程池:"+Thread.currentThread().getName()+"--paymentInfo_TimeOut,id: "+id+"/t"+"哈哈耗时:"+time+"秒";
    }

    public String payment_TimeOutHandler(Integer id){
        return  "线程池:"+Thread.currentThread().getName()+"--paymentInfo_TimeOut,id: "+id+"/t"+"####系统繁忙呜呜呜##";
    }
}
Controller层
@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;
    @Value("${server.port}")
    private String serverPort;
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id")Integer id){
        String result = paymentService.paymentInfo_OK(id);
        log.info("&&&&&&result"+result);
        return result;
    }
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_timeout(@PathVariable("id")Integer id){
        String result = paymentService.paymentInfo_TimeOut(id);
        log.info("*******result"+result);
        return result;
    }
}

6.   测试

 出现情况:

Tomcat的默认的工作线程数被打满了,没有多余的线程来分解压力和处理。出现两个都在自己转圈圈。

上述结论

 

如何解决?解决的要求

创建cloud-consumer-feign-hystrix-order80消费端

Pom

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>com.fengyangcai.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

Yml

server:
  port: 80
spring:
  application:
    name: cloud-consumer-feign-hystrix-order
eureka:
  client:
    register-with-eureka: false #表示是否将自己注册进EurekaServer默认为true
    fetch-registry: true #是否从EurekaServer捉取已有的注册信息,默认为true.单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka
      defaultZone: http://localhost:7003/eureka

主函数

其中@EnableCircuitBreaker就是引入了hystrix的熔断注解标签

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class FeignHystrixOrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignHystrixOrderMain80.class,args);
    }
}

使用openFeign在service层调用服务

@Component
@FeignClient(value = "cloud-provider-hystrix-payment")
public interface PaymentFeignHystrixService {
    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id")Integer id);

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_timeout(@PathVariable("id")Integer id);

}

Controller层

其中@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")是全局的一个处理方法标签。

@HystrixCommand是hystrix的一个处理标签。

@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderFeignHystrixController {

    @Resource
    private PaymentFeignHystrixService paymentFeignHystrixService;

    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id")Integer id){
        return paymentFeignHystrixService.paymentInfo_OK(id);
    }
    //一般Hstrix降级放在客户端
    @GetMapping("/payment/hystrix/timeout/{id}")
   /* @HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
    })*/
    @HystrixCommand
    public String paymentInfo_timeout(@PathVariable("id")Integer id){

        return paymentFeignHystrixService.paymentInfo_timeout(id);
    }

    public String payment_TimeOutHandler(Integer id){
        return  "我是消费方80.对方支付系统繁忙请稍后访问";
    }
    //全局fallback方法
    public String payment_Global_FallbackMethod(){
        return "全局的降级处理方法";
    }
}

 上面是使用了服务降级的配置

@HystrixCommand
在官网上是程序,工程落地都是使用配置方式

@HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
中,fallbackMethod是回路的执行方法,1500代表1.5秒,执行超过这个时间就执行回路方法。

 总结一下使用

引入依赖,在yml文件中配置

feign:
  hystrix:
    enabled: true
在启动类上加上
@EnableHystrix,如果是熔断加@EnableCircuitBreaker
业务类方法上加 @HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
这个导致代码膨胀,每个业务方法对应了一个兜底的方法。我们要统一和自定义的分开。

在feign的接口上配置
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")其中 payment_Global_FallbackMethod就是兜底的方法。

 

这样还是把处理的兜底方法放在同一个类啊。

 

下面我们解决这个问题

为Feign客户端定义的接口添加一个服务降级处理的实现类

@Component
public class PaymentFallbackService implements PaymentFeignHystrixService{
    @Override
    public String paymentInfo_OK(Integer id) {
        return "-----PaymentFallbackService fall back";
    }

    @Override
    public String paymentInfo_timeout(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_timeout";
    }
}

 在yml上要加上

 

 Hystrix之服务熔断理论

 大师的论文:https://martinfowler.com/bliki/CircuitBreaker.html

实操

修改我们上面的服务提供工程cloud-provider-hystrix-payment8001

配置PaymentService

  //======服务熔断
    @HystrixCommand(fallbackMethod ="paymentCircuitBreaker_fallback",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),//失败率达到多少后跳闸
    })
    public String paymentCircuitBreaker(@PathVariable("id")Integer id){
        if (id<0){
            throw new RuntimeException("***********id 不能为负数");
        }
        //使用hutool工具吧创建一个没有-的字符串
        String serialNumber = IdUtil.simpleUUID();
        return  Thread.currentThread().getName()+"	"+"调用成功,流水号为: "+serialNumber;
    }

    public String  paymentCircuitBreaker_fallback(@PathVariable("id")Integer id){
        return "id 不能为负数,请稍后再试,--paymentCircuitBreaker_fallback";
    }

why配置这些参数?

intellj idea 使用ctrl+N的查看HystrixCommandProperties 类,这个类记载了HystrixCommand的全部属性

在controller层

 //====服务熔断
    @GetMapping("/payment/hystrix/paymentCircuitBreaker")
    public String paymentCircuitBreaker(@PathVariable("id")Integer id){

        String result = paymentService.paymentCircuitBreaker_fallback(id);
        log.info("****result:"+result);
        return result;
    }

测试

 结论

 官网断路器流程图

 断路器在什么情况下开始起作用?

 

 断路器打开之后

 所有的配置

 

 

服务限流

参照alibaba的sentinel说明

hystrix的工作流程

https://github.com/Netflix/Hystrix/wiki/How-it-Works

官网图例

网上找

服务监控hystrixDashboard

概述

仪表盘9001

新建cloud-consumer-hystrix-dashboard9001

pom

 <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

yml

server:
  port: 9001

hystrixDashboardMain9001 +新的注解@EnableHystrixDashboard

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardMain9001.class,args);
    }
}

所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置

启动cloud-consumer-hystrix-dashboard9001该微服务后续将监控微服务8001

http://localhost:9001/hystrix

 

 要在监控的主启动类上配置

 使用观察监控窗口

填写监控地址http://localhost:8001/hystrix.stream

 测试地址

 

 

 

 

 















原文地址:https://www.cnblogs.com/fengyangcai/p/13303490.html