SpringCloud-2.0-周阳(10. 服务降级 - Hystrix - 引出问题)学习笔记

上一篇 : 9. 负载均衡 - OpenFeign

下一篇 :11. 服务降级 - Hystrix - 解决问题

  • Hystrix官宣,停更进维

1. 概述

1.1 雪崩效应

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。
在这里插入图片描述
对于高流量的应用来说,单一的后端服务可能会导致所有服务器上的所有资源都在几秒钟内饱和。更糟的是,这样应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离、管理,以便单一依赖关系的失败,不能取消整个应用程序。

1.2. 什么是Hystrix

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等, Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

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

1.3. Hystrix的作用

  • 提供保护并控制通过第三方客户端库(通常是通过网络)访问的依赖项的延迟和失败。
  • 服务熔断 :停止复杂的分布式系统中的级联故障。
  • 快速失败,迅速恢复。
  • 服务降级 :回退并在可能的情况下正常降级。
  • Hystrix-Dashboard流监控 :启用近乎实时的监视,警报和操作控制。

2. Hystrix重要概念

2.1 服务降级

  • 服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback
  • 哪些情况会触发降级
  • 程序运行异常
  • 超时
  • 服务熔断触发服务降级
  • 线程池 / 信号量打满也会导致服务降级

2.2 服务熔断

  • 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
  • 服务的降级->进而熔断->恢复调用链路

2.3 服务限流

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

3. Hystrix 环境搭建

3.1 Provider 搭建

  1. 新建模块 :cloud-provider-payment-Hystrix-8007

  2. 修改 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.demo.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>
    
  3. 编写 YML

    server:
      port: 8007
    
    eureka:
      client:
        #表识不向注册中心注册自己
        register-with-eureka: true
        #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
        fetch-registry: true
        service-url:
          #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
          defaultZone: http://localhost:7001/eureka, http://localhost:7002/eureka
    
    spring:
      application:
        name: cloud-provider-hystrix-payment
    
  4. 编写主启动类

    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentHystrixMain8007 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentHystrixMain8007.class,args);
        }
    }
    
  5. 业务类

  • Service

    PaymentService

    public interface PaymentService {
        //成功
        public String paymentInfo_OK(Integer id);
        //失败
        public String paymentInfo_TimeOut(Integer id);
    }
    

    PaymentServiceImpl

    @Service
    public class PaymentServiceImpl implements PaymentService {
        //成功
        @Override
        public String paymentInfo_OK(Integer id){
            return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_OK,id:  "+id+"\t"+"哈哈哈"  ;
        }
        //失败
        @Override
        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;
        }
    }
    
  • Controller :PaymentController

    @RestController
    @Slf4j
    public class PaymentController {
    
        @Autowired
        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;
        }
    }
    
  1. 测试

    启动 Eureka-7001、provider-Hystrix-8007

    访问 http://localhost:8007/payment/hystrix/ok/31
    在这里插入图片描述

    访问 http://localhost:8007/payment/hystrix/timeout/31
    在这里插入图片描述
    访问正常,继续下面的操作

  • 上述在非高并发情形下,还能勉强满足
  • 下面测试一下高并发的情况

3.2 Jmeter压测测试

  1. 打开 Jmeter

  2. 新建一个测试计划
    在这里插入图片描述

  3. 配置线程组
    在这里插入图片描述

  4. 添加 HTTP 请求
    在这里插入图片描述

  5. 进行配置
    在这里插入图片描述

  6. 保存,启动
    在这里插入图片描述

  7. 刷新之前的两条请求

    发现都会变慢一点

    如果并发量更大,就会更慢,甚至卡死

4. 加上 Consumer- Hystrix

4.1 环境搭建

  1. 新建 cloud-consumer-feign-hystrix-order-80

    使用 Feign 做负载均衡

  2. 修改 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.demo.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>
    
  3. 编写 YML

    server:
      port: 80
    
    spring:
      application:
        name: cloud-provider-hystrix-order
    
    eureka:
      client:
        register-with-eureka: true
        fetchRegistry: true
        service-url:
          defaultZone: http://localhost:7001/eureka, http://localhost:7002/eureka
    
  4. 编写主启动类

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

  • PaymentHystrixService

    @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);
    }
    
  • OrderHystrixController

    @RestController
    @Slf4j
    public class OrderHystrixController {
    
        @Autowired
        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;
        }
    }
    
  1. 测试

    访问 :http://localhost/consumer/payment/hystrix/ok/31

    在这里插入图片描述

4.2 高并发测试

  1. 启动 Jmeter

  2. 访问 Consumer 的服务

    发现也开始变得有点慢了。

4.3 原因分析

  • 8007 同一层次的其他接口服务被困死
  • 因为tomcat线程里面的工作线程已经被挤占完毕
  • 这就会导致 8007 访问其他服务时也会变卡
  • 80此时调用 8007,客户端访问响应缓慢,转圈圈
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yuan_404

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

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

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

打赏作者

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

抵扣说明:

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

余额充值