08.微服务防雪崩利器之Hystrix

Posted 潮汐先生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了08.微服务防雪崩利器之Hystrix相关的知识,希望对你有一定的参考价值。

微服务防雪崩利器之Hystrix

前言

上一节中我们说Hystrix是微服务中防止服务雪崩的利器,但它是Netflix之前开源的一个组件,发展到今天也已经和Eureka与Ribbon一样进入到了维护模式,后面我们会用学习阿里的sentinel(基于Hystrix)。但是作为曾经最火爆的组件之一还是有必要学习一下的

Hystrix

概念

Hystrix是一个库,它通过添加延迟容忍和容错逻辑来帮助您控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止它们之间的级联故障以及提供后备选项来实现这一点,所有这些都可以提高系统的整体弹性

通俗定义: Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖不可避免的会调用失败、超时、异常等;Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障(服务雪崩现象),提高分布式系统的弹性。

熔断条件

  • 当满足一定的阀值的时候(默认10秒内超过20个请求次数)

  • 当失败率达到一定的时候(默认10秒内超过50%的请求失败)

到达以上阀值,断路器将会开启。当开启的时候,所有请求都不会进行转发。 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启,如此反复

断路器流程

简单使用

1. 启动consul

首先win+R启动命令行窗口,输入consul agent -dev启动我们的服务注册中心

2.新建Module

我们新建一个Module - 05.springcloud_hystrix,点击Finish

3.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>com.christy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>05.springcloud_hystrix</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- springboot依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入consul client依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!-- 引入健康检查依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- 引入Hystrix组件 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>
</project>

4.application.properties

server.port=8900
spring.application.name=HYSTRIX

# 注册到consul server
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500

5.HystrixApplication.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @Author Christy
 * @Date 2021/6/10 15:08
 **/
@SpringBootApplication
// 代表服务注册中心客户端
@EnableDiscoveryClient
// 开启Hystrix服务熔断
@EnableCircuitBreaker
public class HystrixApplication 
    public static void main(String[] args) 
        SpringApplication.run(HystrixApplication.class, args);
    

6.HystrixController.java

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author Christy
 * @Date 2021/6/10 15:11
 **/
@RestController
@RequestMapping("hystrix")
public class HystrixController 

    @RequestMapping("test")
    /**
     * fallbackMethod:自定义快速响应失败方法
     * defaultFallBack:如果没有特殊情况我们可以使用Hystrix提供的统一默认快速响应处理方法
     *                  这样可以避免Controller中的每个方法都自定义一个快速失败的响应
     * 如果同时写上上面两个,则以前者为准
     */
    @HystrixCommand(fallbackMethod = "testHystrixFallBack",defaultFallback = "defaultFallback")
    public String testHystrix(Integer id)
        System.out.println("Hystrix test OK!");
        if(id <= 0)
           throw new RuntimeException("id必须大于0!");
        

        return "Hystrix test ok!";
    

    /**
     * 默认速响应失败方法
     * 默认的快速响应失败方法不需要跟原方法保持一致
     */
    public String defaultFallback()
        return "网络拥堵,请稍后再试……";
    

    /**
     * 自定义快速响应失败方法
     * 参数和返回值必须和testHystrix方法一致
     */
    public String testHystrixFallBack(Integer id)
        return "网络故障,服务已经被熔断处理!";
    

7.测试

我们启动项目,在浏览器中输入http://localhost:8900/hystrix/test?id=1http://localhost:8900/hystrix/test?id=0查看效果

这个时候虽然id=0的时候返回的是网路故障,服务已经被熔断处理但是此时的服务并没有被熔断。如果服务熔断后正常的访问是访问不了的。

下面我们来模拟一下服务熔断的过程

当我们10秒内访问失败次数大于20的时候,这个时候开启了熔断;此时我们的正常访问也会进入到快速熔断。等过了5秒之后,我们再次正常访问就会返回正常的结果。

OpenFeign+Hystrix实现服务降级

正常访问无降级

1.新建Module

2.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>com.christy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>05.springcloud_hystrix_openfeign</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- springboot依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入consul client依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!-- 引入健康检查依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!--引入openfeign依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
</project>
3.application.properties
server.port=8901
spring.application.name=HYSTRIXOPENFEIGN

#注册服务中心
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
4.HystrixOpenFeignApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author Christy
 * @Date 2021/6/10 16:05
 **/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class HystrixOpenFeignApplication 
    public static void main(String[] args) 
        SpringApplication.run(HystrixOpenFeignApplication.class, args);
    

5.HystrixClient.java
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @Author Christy
 * @Date 2021/6/10 16:09
 **/
@FeignClient(value = "HYSTRIX")
public interface HystrixClient 
    @GetMapping("/hystrix/test")
    String testHystrix(@RequestParam("id") Integer id);

6.HystrixOpenFeignController.java
import com.christy.feignclients.HystrixClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author Christy
 * @Date 2021/6/10 16:11
 **/
@RestController
@RequestMapping("/hystrix/openfeign/")
public class HystrixOpenFeignController 

    @Autowired
    private HystrixClient hystrixClient;

    @RequestMapping("/test")
    public String test()
        System.out.println("hystrix openfeign test ok!");
        String hystrixResult = hystrixClient.testHystrix(1);
        System.out.println("hystrix result : "+hystrixResult);
        return "hystrix openfeign test ok ";
    

7.测试

上面的代码所实现的功能即服务HYSTRIXOPENFEIGN中调用HYSTRIX里面的方法,现在我们分别启动这两个服务然后浏览器输入http://localhost:8901/hystrix/openfeign/test来看下调用结果

上面的结果显示我们的调用成功了。现在我们把HYSTRIX服务停掉,再次访问发现无法找到映射

通过以上的结果我们想一下能够在OpenFeign这段也加上Hystrix,当服务不可用时进行熔断,执行快速失败响应结果呢?这个是可以的,下只不过这个时候不能叫熔断了,应该叫服务降级

实现服务降级

1.引入依赖

如果想要在OpenFeign端实现服务降级就需要引入Hystrix的依赖,所幸的是consul和OpenFeign中都已经依赖了Hystrix,所以我们这里就不需要单独引入Hystrix了

2.开启Hystrix支持

HYSTRIXOPENFEIGN服务的配置文件中添加Hystrix的支持

# 开启openfeign在调用服务过程中 开启hystrix支持 默认:就是没有开启
feign.hystrix.enabled=true
3.HystrixClient.java

在注解@FeignClient中有个属性fallback,不过他的值是一个class(这里指的是当前注解标注的接口的实现类),我们新建一个实现类就叫做HystrxiClientFallBack.java

package com.christy.feignclients;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @Author Christy
 * @Date 2021/6/10 16:09
 **/
@FeignClient(value = "HYSTRIX",fallback = HystrixClientFallBack.class)
public interface HystrixClient 
    @GetMapping("/hystrix/test")
    String testHystrix(@RequestParam("id") Integer id);

4.HystrxiClientFallBack.java
import org.springframework.stereotype.Component;

/**
 * @Author Christy
 * @Date 2021/6/10 16:32
 **/
@Component
public class HystrixClientFallBack implements HystrixClient
    @Override
    public String testHystrix(Integer id) 
        return "当前服务不可用!";
    

5.测试

以上工作完毕后我们只启动服务HYSTRIXOPENFEIGN,然后浏览器输入http://localhost:8901/hystrix/openfeign/test,可以看到当前服务并没有报错,但是控制台输出了当前服务不可用

当我们再次把服务HYSTRIX启动,发现控制台可以正常输出结果

至此呢在服务调用端的服务降级功能我们就实现了

补充说明

Hystrix其实还有一个知识点就是Hystrix DashBoard,不过这个DashBoard已经被废弃了,后面我们会使用Sentinel DashBoard来替代它,所以这里暂时没有计划对Hystrix DashBoard进行详细说明,如果有必要后期再写吧ヾ(◍°∇°◍)ノ゙

以上是关于08.微服务防雪崩利器之Hystrix的主要内容,如果未能解决你的问题,请参考以下文章

防雪崩利器 hystrix-go 源码分析

防雪崩利器:熔断器 Hystrix 的原理与使用

防雪崩利器:熔断器 Hystrix 的原理与使用

防雪崩利器:熔断器 Hystrix 的原理与使用(转)

Spring Cloud Hystrix - 服务容错

分布式服务防雪崩熔断器,Hystrix理论+实战。