Hystrix断路器


尚硅谷,周阳教程的学习笔记

概述

官方:https://github.com/Netflix/Hystrix/

由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。

为了解决这个问题,业界提出了断路器模型。

在这里插入图片描述

较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次) 断路器将会被打开。
在这里插入图片描述
在这里插入图片描述

为何用Hystrix?

为了避免单个服务故障导致服务“雪崩”效应。
如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成“雪崩”

服务提供者cloud-provider-hystrix-payment8001

pom

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

application.yml

server:
  port: 8001


eureka:
  client:
    register-with-eureka: true    #向注册中心注册自己
    fetch-registry: true   #需要去检索服务
    service-url:
 
      defaultZone: http://eureka7001.com:7001/eureka/
spring:
  application:
    name: cloud-provider-hystrix-payment

启动类

/**
 * @(#)PaymentHystrixMain8001.java, 2020/12/7.
 * <p/>
 * Copyright 2020 Netease, Inc. All rights reserved.
 * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author lvhouhou(lvhouhou @ 163.com)
 */

@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {

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

使用JMeter进行高并发压测

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

开启后再通过浏览器访问
http://localhost:8001/payment/hystrix/ok/111
发现请求回应变慢了

在这里插入图片描述

消费者cloud-consumer-hystrix-order80

pom

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

        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

application.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-consumer-feign-hystrix-order


启动类

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

当启动JMeter压测之后,消费端等待服务提供方时间延长

在这里插入图片描述

服务降级

解决

超时、异常、宕机等问题。
在这里插入图片描述
在这里插入图片描述

服务提供方和消费方均可配置服务降级。

一般用的较多的是消费方服务降级

服务方服务降级cloud-provider-hystrix-payment8001

业务类

在这里插入图片描述
上图故意制造了两个异常: 计算异常: int age = 5/0 ,超时异常:我么们能接受3s,但它需要5s

上述情况出现即当前服务不可用了,作服务降级

主要使用HystrixCommand注解,fallbackNMethod指定了超时、异常发生后的降级方法

   //====服务降级

    @GetMapping("/lower/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
    })
    public String paymentInfo_TimeOutLower(@PathVariable("id") Integer id)
    {
        int timeNumber = 5;
        //int age = 5/0;

        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOutLower id:" + id + "哈哈哈";
    }
    // 兜底方法
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "我是服务提供者8001,系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o--报错";
    }

启动类

需添加@EnableCircuitBreaker注解

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {

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

结果

如预期
在这里插入图片描述

消费方服务降级

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

完整


  server:
    port: 80


  eureka:
    client:
      register-with-eureka: true
      fetch-registry: true
      service-url:
        defaultZone: http://eureka7001.com:7001/eureka/

  spring:
    application:
      name: cloud-consumer-feign-hystrix-order

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


启动类

需添加@EnableHystrix注解

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

业务类

主要使用HystrixCommand注解,fallbackNMethod指定了超时、异常发生后的降级方法

在这里插入图片描述

 @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
    })
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        int age = 10/0;
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }

结果

在这里插入图片描述

注意事项

热部署方式对JAVA代码的改动明显,但对HystrixCommand内属性的修改不敏感,建议重启微服务

以上服务降级存在的问题

- 每个方法都配置一个兜底方法,代码膨胀(冗余)
- 兜底方法和业务逻辑耦合在一起, 十分混乱

以下通过全区服务降级解决第一个问题,通配服务降级解决第二个问题

全局服务降级

以服务消费方为例
在上述基础上,只需变更业务类

业务类

一般的方法用全局服务降级,特殊的再用上面的一个方法一个特定的服务降级。

全局服务降级,使用@DefaultProperties(defaultFallback = “payment_Global_FallbackMethod”)指定全局兜底方法,而业务方法使用 @HystrixCommand标记即可
在这里插入图片描述

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-20 11:57
 */
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystirxController
{
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
   /* @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
    })*/
    @HystrixCommand
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        int age = 10/0;
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }

    // 下面是全局fallback方法
    public String payment_Global_FallbackMethod()
    {
        return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
    }
}

通配服务降级

以消费方降级为例。
只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦。

Feign服务接口

@FeignClient的注解fallback属性指明实现类(兜底方法)

在这里插入图片描述

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" ,fallback = PaymentFallbackService.class)
//@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);
}

Feign服务接口的实现

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

    @Override
    public String paymentInfo_TimeOut(Integer id)
    {
        return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
    }
}

业务类

这里没有使用@HystrixCommand注解,而是将fallback方法与Feign结合,写在了@FeignClient注解中

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

结果

8001正常时:
在这里插入图片描述
8001宕机时:
在这里插入图片描述

服务熔断

服务熔断就是保险丝, 服务降级–>熔断–>恢复调用链路

熔断机制概述

熔断机制是应对雪崩效应的一种微服务链路保护机制,当链路中某个微服务出错不可用或相应时间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回错误相应信息。
当检测到该节点微服务调用相应正常后,恢复调用链路。
再SpringCloud中通过Hystrix实现。它会监控微服务键调用的状况,当失败的调用到一定阈值(缺省,10秒内,20以上的请求,50%失败率),就会启动熔断机制。熔断机制的注解是@HystrixCommand。

实操

服务方cloud-provider-hystrix-payment8001

业务类

在这里插入图片描述

package com.atguigu.springcloud.service;

import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Service
public class 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 不能负数,请稍后再试,/(ㄒoㄒ)/~~   id: " +id;
    }

}

可配置项在HystrixCommandProperties文件
在这里插入图片描述
controller

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

在这里插入图片描述
结果如预期

总结

- 什么情况触发熔断?
根据@HystrixCommand注解配置的条件触发熔断
三个重要参数:快照时间、请求次数阈值、失败百分比阈值
(默认10秒内,20以上的请求,50%失败率),

- 熔断后请求是如何执行的?
再有请求调用的时候,将不会调用链路主逻辑,直接调用降级fallback,减少了响应延迟
- 熔断后是如何恢复调用链路的?
Hystrix有自动恢复的功能,有一个参数休眠时间(默认5秒),休眠时间内降级fallback,休眠期到达后断路器是半开启状态,会释放一次请求到原来的主逻辑,如果请求正常返回,表示服务正常,熔断关闭,如果依然有问题,熔断继续打开,休眠时间重新计时。

在这里插入图片描述

服务限流(这里没讲,后面alibaba的Sentinel)

Hystrix工作流程

官网说明:https://github.com/Netflix/Hystrix/wiki/How-it-Works

下图显示了通过Hystrix向服务依赖项请求时发生的情况:
在这里插入图片描述
在这里插入图片描述

Hystrix图形化Dashborad搭建

在这里插入图片描述

新建监控项目cloud-consumer-hystrix-dashboard9001

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>

application.yml

server:
  port: 9001

启动类

新注解@EnableHystrixDashboard


package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

/**
 * @author lvhouhou(lvhouhou @ 163.com)
 */

@SpringBootApplication
@EnableHystrixDashboard
public class DashboardMain9001 {

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

启动后访问:
http://localhost:9001/hystrix
如下:
在这里插入图片描述

被监控的服务

pom文件须有以下依赖


        <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>

启动类添加方法

  /**
     * Dashboard仪表盘监控
     * @return
     */
    @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;
    }

如:
在这里插入图片描述
不写的话可能出现
在这里插入图片描述

监控页面

填写监控地址

在这里插入图片描述


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

在这里插入图片描述

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值