【真会玩】- SpringCloud Netflix 实战笔记 -【Hystrix】


在这里插入图片描述

友情提醒

  • 文末获取【真会玩】- SpringCloud Netflix 实战系列Postman在线脚本Github仓库实战源码
  • 【真会玩】- SpringCloud Netflix 实战系列有概念有实战,考验动手能力,如果实战中有操作没有达到与本文同等效果的请先仔细检查个人操作与文中相关内容是否一致,如检查无误请私信或评论区留言~

在这里插入图片描述

Hystrix

在分布式环境中,存在许多服务依赖关系,但是这些服务中必然存在交互失败的问题

  • Hystrix通过超时机制断路器模式,帮我们控制这些分布式服务之间的交互
  • Hystrix通过隔离服务之间的访问点( 远程系统、服务或者第三方库)停止跨服务的级联故障以及提供回退选项来实现这一点,提高了系统的整体弹性(可用性与容错性)。
  • Hystrix提供了监控,可以实时监控运行指标配置的变化,提供近实时的监控、报警、运维控制。
  • Hystrix提供了系统保护机制,在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
  • Hystrix提供了跳闸机制,当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
  • Hystrix提供了回退机制(Fallback),当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供优雅的服务降级。
  • Hystrix实现了资源隔离,为每个请求都的依赖都维护了一个小型线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。
  • Hystrix实现了快速失败(Fail Fast),不去真正的请求服务,发生异常再返回,而是直接失败,同时也能快速恢复
  • Hystrix实现了包裹请求,使用HystrixCommand / HystrixObservableCommand包裹对依赖的调用逻辑,每个命令在独立线程中运行。
  • Hystrix实现了自我修复,断路器打开一段时间后自动进入半开状态,可以进行打开/关闭,半开状态的转换。下面实战的时候会有相关介绍。

降级

向服务方发起请求,判断连接超时

  • 将这次请求记录到服务
  • 尝试向其他服务器发起请求,还是没有请求成功
  • catch异常
    • 可以返回重试页面,提供重试入口
    • 返回提示信息

隔离

线程隔离(限流)

每发起一个Http请求都会开一个独立线程去处理业务,涉及到了线程消耗的问题,为了避免造成线程任务积压

  • 当线程数达到线程池线程数上限的时候直接抛出异常,后面来的任务全部不处理,只处理之前还没处理完的请求,这叫隔离/限流

熔断

我们在向服务方发起请求失败了,给连续失败次数计数

  • 达到阈值的时候抛出异常进入异常处理逻辑

依赖集成

Feign-Consume服务请求方添加如下依赖

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

举个例子🌰

直接使用

new HystrixTest类,继承HystrixCommand抽象类,实现rungetFallback方法

public class HystrixTest extends HystrixCommand {
    public static void main(String[] args) {
        Future<String> future = new HystrixTest(HystrixCommandGroupKey.Factory.asKey("doProcess")).queue();
        String reslut = "";
        try {
            reslut = future.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("reslut:" + reslut);
    }


    @Override
    protected Object run() throws Exception {
        System.out.println("开始执行...");
        //制造异常场景,都知道1/0在java中会抛出ArithmeticException(算术异常)对吧
        int i = 1 / 0;
        return "执行成功...";
    }

    /**
     * 备用逻辑
     *
     * @return java.lang.Object
     * @author Rhys.Ni
     * @date 2022/9/26
     */
    @Override
    protected Object getFallback() {
        return "异常了,走到了getFallback逻辑";
    }

  	//有很多种构造函数,我们只需要一种就可以了
    public HystrixTest(HystrixCommandGroupKey group) {
        super(group);
    }
}

运行从结果可以看出程序进了run方法并执行算法抛出了异常,那么异常了程序后续该怎么执行呢?

在这里插入图片描述

当程序抛出异常时则会进入备用逻辑getFallback方法中,成功执行了备用方法里面的逻辑

在这里插入图片描述

Feign整合Hystrix

Fallback

Feign-Consumer服务application.yml配置文件中添加以下配置

  • 默认是关闭的
feign:
  hystrix:
    enabled: true

new FeignProviderBack类,实现FeignConsumerApi接口,将接口内所有方法都重新实现一遍,这种形式的降级策略就是针对于每一个独立请求的降级

@Component
public class FeignProviderBack implements FeignConsumerApi {

    @Override
    public String pingFeignProvider() {
        return "降级了,返回了兜底数据";
    }
}

@FeignClient注解中添加属性fallback = FeignProviderBack.class

@FeignClient(name = "FeignProvider",fallback = FeignProviderBack.class)
public interface FeignConsumerApi extends ServiceApi {
}

ServiceApi中有一点需要注意

  • 不能在类上加@RequestMapping注解,否则启动的时候会重复创建两次相同的方法且抛异常启动失败

在这里插入图片描述

在这里插入图片描述

因此,我们需要去掉ServiceApi上的@RequestMapping注解

在这里插入图片描述

我们调用一下http://localhost:9080/testOpenFeign接口

  • 可以看到确实走进了FeignProviderBack中的降级逻辑

在这里插入图片描述

FallbackFactory

@FeignClient注解中替换属性fallback = FeignProviderBack.classfallbackFactory = FeignProviderBackFactory.class

@FeignClient(name = "FeignProvider",fallbackFactory = FeignProviderBackFactory.class)
public interface FeignConsumerApi extends ServiceApi {
}

new FeignProviderBackFactory类,实现FallbackFactory接口

  • 这边可以针对具体业务的Api使用,这里我针对FeignConsumerApi来使用
public class FeignProviderBackFactory implements FallbackFactory<FeignConsumerApi> {
    @Override
    public FeignConsumerApi create(Throwable throwable) {
        return new FeignConsumerApi() {
            @Override
            public String pingFeignProvider() {
                return "FallbackFactory 实现降级了,返回了兜底数据";
            }
        };
    }
}

重启Feign-Consumer服务,再次调用http://localhost:9080/testOpenFeign接口

  • 可以看到也是生效了的

在这里插入图片描述

除此以外我们还可以根据异常类型进行判断执行不同的处理逻辑

@Component
public class FeignProviderBackFactory implements FallbackFactory<FeignConsumerApi> {
    @Override
    public FeignConsumerApi create(Throwable throwable) {
        return new FeignConsumerApi() {
            @Override
            public String pingFeignProvider() {
                if (throwable instanceof RuntimeException) {
                    return "请求时异常:" + throwable;
                } else {
                    return "FallbackFactory 实现降级了,返回了兜底数据";
                }
            }
        };
    }
}

RestTemplate整合Hystrix

  • 在启动类FeignConsumerApplication加上@EnableCircuitBreaker注解支持Hystrix
    • 有的兄弟可能会问那刚刚Feign集成Hystrix的时候为什么没加这个注解也可以实现?
      • 因为Feign默认支持Hystrix,只需要在配置文件中控制配置开关即可
  • 在启动类声明RestTemplate为单例Bean
@EnableFeignClients
@EnableCircuitBreaker
@SpringBootApplication
public class FeignConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignConsumerApplication.class, args);
    }

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

new TestRestService

  • @HystrixCommand(defaultFallback = “testFallBack”)
    • testFallBack为方法名,所以要新增方法testFallBack
@Service
public class TestRestService {

    @Resource
    private RestTemplate restTemplate;

    @HystrixCommand(defaultFallback = "testFallBack")
    public String testOpenFeignWithRest() {
        String url = "http://FeignProvider/pingFeignProvider";
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            String result = responseEntity.getBody();
            return result;
        } else {
            return "Bad Request";
        }
    }

    private String testFallBack() {
        return "@HystrixCommand 实现了降级,返回了兜底数据";
    }
}

FeignConsumerController中新增接口/testOpenFeignWithRest

  • 注入TestRestService服务
@RestController
public class FeignConsumerController {
    @Resource
    private FeignConsumerApi feignConsumerApi;

    @Resource
    private TestRestService restService;

    @GetMapping("/testOpenFeign")
    public String testOpenFeign() {
        return feignConsumerApi.pingFeignProvider();
    }

    @GetMapping("/testOpenFeignWithRest")
    public Object testOpenFeignWithRest() {
        return restService.testOpenFeignWithRest();
    }
}

重启服务调用/testOpenFeignWithRest接口

http://localhost:9080/testOpenFeignWithRest

可以看到咱们走到TestRestService中逻辑成功降级了

在这里插入图片描述

线程隔离&信号量隔离

默认情况下hystrix使用线程池控制请求隔离

  • 线程池隔离:用 Hystrix 自己的线程去执行调用

  • 信号量隔离:直接让 tomcat 线程去调用依赖服务

    • 信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行
    • 信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。

监控线程池隔离

监控线程池隔离开启dashboard

Feign-Consumer服务调用方添加如下依赖

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

Feign-Consumer启动类添加@EnableHystrixDashboard注解

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

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

Feign-Consumer配置文件application.yml中添加以下配置开启所有端点

#开启所有Actuator Web访问端口
management:
  endpoints:
    web:
      exposure:
        include: "*"

#配置主机地址白名单
hystrix:
  dashboard:
    proxy-stream-allow-list: "localhost"
  • 重启Feign-Consumer服务,打开图形监控页面
localhost:9080/hystrix

输入监控上报接口地址

http://localhost:9080/actuator/hystrix.stream

image-20220926123305957

image-20220926115845228

进入页面后得调用其他接口让数据进行统计,让页面动起来

Pool Size:线程池大小,有多少个线程

在这里插入图片描述

监控信号量隔离

想要在dashboard中监控信号量隔离状态,需要在配置文件中修改隔离策略配置

  • 默认Thread策略, ThreadSemaphore
  • Thread 通过线程数量来限制并发请求数,可以提供额外的保护,但有一定的延迟。一般用于网络调用
  • SEMAPHORE 通过Semaphore Count来限制并发请求数,适用于无网络高并发请求

隔离策略配置

hystrix:
  #隔离策略配置
  command:
    default:
      execution:
        isolation:
          strategy: Semaphore

重启再次刷新页面,调用其他接口增加信息上报数据流动

因为我们这次切换成了SEMAPHORE信号量隔离,可以看到Thread Pools栏里是没有相关信息数据的

image-20220926153443448

其他配置

hystrix:
  dashboard:
    #配置主机地址白名单
    proxy-stream-allow-list: "localhost"
  #隔离策略配置
  command:
    default:
      execution:
        isolation:
          strategy: Semaphore
          thread:
            #命令执行超时时间,默认1000ms
            timeoutInMilliseconds: 1000
            #发生超时是是否中断
            interruptOnTimeout: true
          semaphore:
            #最大并发请求数
            #默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效
            #如果达到最大并发请求数,请求会被拒绝
            #理论上选择semaphore size的原则和选择thread size一致
            #但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread
            maxConcurrentRequests: 10
        #执行是否启用超时,默认启用true
        timeout:
          enabled: true

在这里插入图片描述

源码&脚本获取地址

  • Postman脚本https://www.getpostman.com/collections/8a0954746646f0dee9a6
    • 脚本可直接复制到Postman使用Link方式导入
  • 实战源码仓库https://github.com/RhysNi/SpringCloudFamilyMeals.git

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倪倪N

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值