10.Hystrix断路器

学习B站尚硅谷周阳老师SpringCloud的听课笔记

1. 概述

1.1分布式系统面临的问题

在这里插入图片描述在这里插入图片描述

1.2.是什么

在这里插入图片描述

1.3.能干嘛

服务降级
服务熔断
服务限流
接近实时的监控

在这里插入图片描述
github地址:

Hystrix官宣,停更进维 ,被动修复bugs,不再接受合并请求,不再发布新版本

2.hystrix案例

2.1 新建cloud-provider-hystrix-payment8001
2.1.1 改pom
<dependencies>
        <!--新增hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
2.1.2改yml
server:
  port: 8001

eureka:
  client:
    register-with-eureka: true    #表识不向注册中心注册自己
    fetch-registry: true   #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    service-url:
      # defaultZone: http://eureka7002.com:7002/eureka/    #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka/
#  server:
#    enable-self-preservation: false
spring:
  application:
    name: cloud-provider-hystrix-payment
#    eviction-interval-timer-in-ms: 2000
2.1.3主启动类与业务类
@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentHystrixMain8001.class,args);
    }
}
@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;
    }
}
@Service
public class PaymentService {

    //成功
    public String paymentInfo_OK(Integer id){
        return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_OK,id:  "+id+"\t"+"哈哈哈"  ;
    }

    //失败
    public String paymentInfo_TimeOut(Integer id){
        int timeNumber = 3;
        try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();}
        return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_TimeOut,id:  "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber;
    }
}
2.1.4正常测试

启动eureka7001,启动cloud-provider-hystrix-payment8001

访问:http://localhost:8001/payment/hystrix/ok/31 和 http://localhost:8001/payment/hystrix/timeout/31

2.1.5 高并发测试

在这里插入图片描述在这里插入图片描述开启Jmeter,来30000个并发压死8001,30000个请求都去访问paymentInfo_TimeOut服务

结果:ok和timeout这两个接口都在转圈圈

why?只是压测timeout接口,ok接口为何会变慢?

tomcat的默认的工作线程数被打满了,没有多余的线程来分解压力和处理。

2.2.cloud-consumer-feign-hystrix-order80
2.2.1改pom
<dependencies>
        <!--新增hystrix-->
        <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>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
2.2.2改yml
server
  port: 80

eureka:
  client:
    register-with-eureka: true    #表识不向注册中心注册自己
    fetch-registry: true   #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    service-url:
             defaultZone: http://eureka7001.com:7001/eureka/

spring:
  application:
    name: cloud-provider-hystrix-order 
2.2.3主启动类与业务类
@SpringBootApplication
@EnableFeignClients
public class OrderHystrixMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderHystrixMain80.class,args);
    }
}
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
@RestController
@Slf4j
public class OrderHystrixController {

    @Resource
    private PaymentHystrixService paymentHystrixService;

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

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_OK(id);
        log.info("*******result:"+result);
        return result;
    }
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        log.info("*******result:"+result);
        return result;
    }
2.2.4测试

http://localhost/consumer/payment/hystrix/ok/31 和 http://localhost/consumer/payment/hystrix/timeout/31

在这里插入图片描述在这里插入图片描述

2. 3服务降级

服务降级可以做在服务端,也可以做在客户端。

2.3.1服务端8001服务降级

主启动类添加注解:@EnableHystrix,具体方法添加@HystrixCommand

设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要有兜底的方法处理,作服务降级fallback

一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法

@Service
public class PaymentService {

    //成功
    public String paymentInfo_OK(Integer id){
        return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_OK,id:  "+id+"\t"+"哈哈哈"  ;
    }

    //失败
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")  //3秒钟以内就是正常的业务逻辑
    })
    public String paymentInfo_TimeOut(Integer id){
       // int timeNumber = 5;
        int age = 10/0;
       // try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();}
        //return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_TimeOut,id:  "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber;
        return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_TimeOut,id:  "+id+"\t"+"呜呜呜"+" 耗时(秒)";
    }

    //兜底方法
    public String paymentInfo_TimeOutHandler(Integer id){
        return "线程池:"+Thread.currentThread().getName()+"   系统繁忙, 请稍候再试  ,id:  "+id+"\t"+"哭了哇呜";
    }

}

在这里插入图片描述

2.3.2客户端80服务降级

80订单微服务,也可以更好的保护自己,自己也依样画葫芦进行客户端降级保护

feign:
  hystrix:
    enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样

主启动类添加注解:@EnableHystrix,具体方法添加@HystrixCommand

当前问题:和业务逻辑混一起???混乱

根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口,重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里面的方法进行异常处理

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

    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_TimeOut , (┬_┬)";
    }
}

在PaymentHystrixService 中注明fallback的类为PaymentFallbackService

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {

    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);

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

}
2.3.3 测试

在这里插入图片描述
在这里插入图片描述
总结:
在客户端和服务端同是配置了服务降级的情况下,如果是客户端设置超时时间在服务端看来是正常情况,则会走客户端的降级逻辑。反之,则走服务端降级逻辑。
如果服务端出现运行时异常,则会走服务端降级逻辑。
如果服务端宕机,则会走客户端降级逻辑。

2.4 服务熔断
2.4.1 熔断是什么?

在这里插入图片描述大神论文:https://martinfowler.com/bliki/CircuitBreaker.html

类比:家里保险丝

2.4.2 演示断路器

修改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 不能负数");
    }
    String serialNumber = IdUtil.simpleUUID();

    return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
    return "id 不能负数,请稍候再试,(┬_┬)/~~     id: " +id;
}

PaymentController

//===服务熔断
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("*******result:"+result);
    return result;
}

测试:

正确:http://localhost:8001/payment/circuit/31
错误:http://localhost:8001/payment/circuit/-31

多次错误,然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行访问,需要慢慢的恢复链路

2.4.3 原理(小总结)

在这里插入图片描述
在这里插入图片描述断路器开启或者关闭的条件

在这里插入图片描述在这里插入图片描述断路器打开后怎么办?

在这里插入图片描述断路器所有的配置项:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

2. 5hystrix工作流程

hystrix工作流程
在这里插入图片描述在这里插入图片描述

3. 服务监控hystrixDashboard

3.1 概述

在这里插入图片描述

3.2 新建cloud-consumer-hystrix-dashboard9001仪表盘服务
3.2.1改pom
<dependencies>
        <!--新增hystrix dashboard-->
        <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-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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
3.2.2改yml
server:
  port: 9001
3.2.3 主启动类

HystrixDashboardMain9001+新注解@EnableHystrixDashboard

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

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

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

注意:新版本Hystrix需要在主启动类MainAppHystrix8001中指定监控路径

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

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

http://localhost:9001/hystrix

9001监控8001
在这里插入图片描述

3.2.5 测试

正确:http://localhost:8001/payment/circuit/31
错误:http://localhost:8001/payment/circuit/-31

先访问正确地址,再访问错误地址,再正确地址,会发现图示断路器都是慢慢放开的

断路器打开
在这里插入图片描述
断路器关闭
在这里插入图片描述

3.2.6 识图(七色一圈一线)

七色:
在这里插入图片描述在这里插入图片描述一圈:
在这里插入图片描述一线:
在这里插入图片描述整图说明:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值