六、Hystrix服务降级与熔断

卑微程序员:各位客官,走过看过,不求三联,只需点赞


SpringCloud系列目录:

  • 一、SpringCloud简介
  • 二、Eureka服务注册与发现
  • 三、Eureka注册与发现之Eureka Comsumer
  • 四、Eureka、Server Provider集群配置
  • 五、Ribbon和OpenFeign
  • 六、Hystrix服务降级与熔断

一、前言

  当今环境下分布式已是当今系统架构的发展方向,但分布式同样面临着许多的问题。本文将从分布式系统面临的问题、解决方案、能解决哪些问题,并结合代码去演示。文章中的代码都已提交到Github,如需自取。

二、分布式系统面临的问题

六、Hystrix服务降级与熔断_第1张图片
服务雪崩:

多个微服务之间调用的时候,假设微服务A调用B和微服务C,微服务B和微服务C又调用其他的服务,这就是所谓的扇出
。如果扇出的连路上某个微服务的调用响应时间过长或者是不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统更崩溃,所谓的“雪崩效应”。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的资源在几秒钟之内饱和。这些应用程序还会导致服务之间的延迟增加,备份队列,现成和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统

解决方案(Hystrix)

当依赖的服务发生故障时,对该服务做降级或者是熔断处理,降低对整个应用的影响
官网地址:https://github.com/Netflix/Hystrix/wiki/How-To-Use
目前Hystrix已不再更新,进入维护阶段。当然以后很多优秀的可用的方案,比如Sentinel。受限于篇幅,此文只涉及服务降级与熔断

2.1 能干什么

1)服务降级

服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好的提示
降级触发:程序运行异常、调用超时、服务熔断触发降级、线程池/信号量打满

2)服务熔断

达到设定的最大的服务访问,直接拒绝访问,然后调用服务降级方法并返回友好提示
熔断过程:服务降级->熔断->恢复调用链路

3)服务限流

秒杀等高并发操作,设定并发量

2.1 服务降级
2.1.1 项目搭建与测试

:项目可以单独建立,不适用Eureka,如果需要使用请参考之前的几篇文章,项目中所有的代码均已提交到github

项目搭建,结构如下:
六、Hystrix服务降级与熔断_第2张图片

1)新建cloud-provider-hystrix-payment8001
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.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>

3)修改yml

server:
  port: 8001

eureka:
  client:
    register-with-eureka: true    #表识不向注册中心注册自己
    fetch-registry: true   #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    service-url:
      #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址(此处我有修改hosts配置文件)
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

spring:
  application:
    name: cloud-provider-hystrix-payment
 

4)主启动类

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

5)业务代码

@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;
    }

}


@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;
    }
}

测试两个接口
先启动两个Eureka服务,然后再启动8001服务,这里我们分别测试两个接口。

在这里插入图片描述
在这里插入图片描述
代码很简单,服务也是可以跑通的。如果在高并发的情况下上述的服务又会如何呢?接下来我们使用Jmater来简单的压测一下,当然在实际的项目中仅仅使用Jmater是远远不够的,此处仅供测试使用

使用压测timeout接口

1)新建一个线程组
六、Hystrix服务降级与熔断_第3张图片
2)在线程组下新建一个http请求
六、Hystrix服务降级与熔断_第4张图片
3)设置协议、服务器名称、端口号、路径
六、Hystrix服务降级与熔断_第5张图片
4)ctrl+s保存之后执行
六、Hystrix服务降级与熔断_第6张图片

5)访问没有休眠的方法发现该方法有了延时
http://localhost:8001/payment/get/info/ok/3
六、Hystrix服务降级与熔断_第7张图片

以上是对服务提供者进行压测,如果有客户端调用8001服务,那结果同样是等待

故障现象和原因

8001同一层次的其他接口服务迪被调用过多,导致tomcat线程中的线程全部被占用,如果再调用8001服务中的其他接口,就需要等待线程被释放。

2.1.2 解决方式
2.2 服务熔断

  • 上一篇 【五、Ribbon和OpenFeign】

你可能感兴趣的:(SpringCloud,Java,Hystrix)