天天看点

Spring Cloud Hystrix 入门

完整源码:https://gitee.com/wan-lianglin/springcloud-test

  1. 什么是Hystrix

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

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

能干嘛

服务降级

服务熔断

熔断机制是对应雪崩效应的一种微服务链路保护机制。

当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。

服务限流

接近实时的监控

官网:Home · Netflix/Hystrix Wiki (github.com)

  1. 来简单测试一下服务熔断

  1. 新建一个模块springcloud-provider-dept-hystrix-9001(直接复制springcloud-provider-dept-8001后修改一下启动类)
Spring Cloud Hystrix 入门

2.导入依赖

<!--Hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
           

3.配置application.yml文件

server:
  port: 9001

#mybatis配置
mybatis:
  type-aliases-package: com.wll.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

#spring配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root

#Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/


#info配置
info:
  app.name: wll-springcloud
  company.name: wll.com
           

4.controller层写方法

package com.wll.springcloud.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.wll.springcloud.pojo.Dept;
import com.wll.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @GetMapping("/dept/get/{id}")
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public Dept get(@PathVariable("id") Long id){
        Dept dept = deptService.queryById(id);
        if (dept==null){
            throw  new RuntimeException("id=>"+id+",不存在该用户,或者信息无法找到~");
        }
        return dept;
    }

    //备选方法
    public Dept hystrixGet(@PathVariable("id") Long id){
        return new Dept()
                .setDeptno(id)
                .setDname("id=>"+id+"没有对应信息,[email protected]")
                .setDb_source("no this database in MySQL");
    }
}
           

在controller层写了get和hystrixGet两个方法,其中hystrixGet方法为备用方法。当get方法出错,就通过@HystrixCommand(fallbackMethod = "hystrixGet")注解来使用hystrixGet方法。

5.在启动类中添加对熔断的支持

package com.wll.springcloud;

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;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

//启动类
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableDiscoveryClient //使服务发现生效
@EnableCircuitBreaker //添加对熔断的支持
public class DeptProviderHystrix_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_9001.class);
    }
}
           

6.启动注册中心,启动服务提供者(DeptProviderHystrix_9001),启动消费者

Spring Cloud Hystrix 入门

id为1查询成功

Spring Cloud Hystrix 入门

id为8,没有这个id,查询失败,并成功调用了备用方法

补充:

7.我们修改消费者的负载均衡算法,修改为轮询(不使用我们自定义的算法)

package com.wll.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WllRule {

    @Bean
    public IRule myRule(){
        return new RoundRobinRule();  //轮询
    }
}
           

3.服务降级

1.在springcloud-api服务中编写DeptClientServiceFallbackFactory类:客户端降级时返回的具体方法,内容

package com.wll.springcloud.service;

import com.wll.springcloud.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

import java.util.List;

//降级
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                return new Dept()
                        .setDeptno(id)
                        .setDname("id=>"+id+"没有对应的信息,客户端提供了降级的信息,这个服务现在已经被关闭")
                        .setDb_source("没有数据~");
            }

            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public boolean addDept(Dept dept) {
                return false;
            }
        };
    }
}
           

2.在springcloud-api服务的DeptClientService类的@FeignClient注解中使用fallbackFactory

package com.wll.springcloud.service;

import com.wll.springcloud.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {

    @GetMapping("/dept/get/{id}")
    public Dept queryById(Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();

    @GetMapping("/dept/add")
    public boolean addDept(Dept dept);

}
           

3.在消费者spring-consumer-dept-feign服务的配置文件application.yml中开启降级feign.hystrix

server:
  port: 8003

# 开启降级feign.hystrix
feign:
  hystrix:
    enabled: true

#Eureka配置
eureka:
  client:
    register-with-eureka: false #不向Eureka注册自己
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
           

4.启动注册中心(,springcloud-eureka-7001),开启降级的消费者(spring-consumer-dept-feign),服务提供者(springcloud-provider-dept-8001):

Spring Cloud Hystrix 入门

可以正常访问

当我们关闭服务提供者后,再访问:

Spring Cloud Hystrix 入门

可以看到返回了我们设置的降级消息。

总结:

按我的理解:服务降级主要是用于客户端,服务熔断是用于服务端。

服务熔断:服务端 某个服务超时或者异常。引起熔断~,调用备用方法,让客户端看不见报错信息,相当于保险丝。

服务降级:客户端 从整体网站请求负载考虑~,当某个服务熔断或者关闭之后,服务将不再被调用~此时在客户端,我们可以准备一个FallbackFactory,返回一个默认的值(缺省值)。

服务降级是我们资源紧张时,主动关闭某个服务器,释放资源。让服务不再被调用,当客户端继续请求这个已经关闭的服务器时,就直接在消费者返回我们设置的内容,提示此服务已关闭。

而服务熔断是在多个服务器链路中,突然有个服务器出错,宕机。为了不使整个服务链路跟着出错,甚至于引发更多连锁错误。我们使用服务熔断,直接返回备用方法。这些都配置在服务端,是被动防止服务器出错。同时还配置了负载均衡算法。

4.dashboard流监控

1.新建一个消费者模块springcloud-consumer-hystrix-dashboard

Spring Cloud Hystrix 入门

2.导入依赖

<?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</artifactId>
        <groupId>com.wll</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-hystrix-dashboard</artifactId>

    <!--实体类web-->
    <dependencies>
        <!--Hystrix依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <!--hystrix-dashboard依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <!--Ribbon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!-- eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.wll</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>
           

3.yml文件

server:
  port: 9002
           

4.启动类

package com.wll.springcloud;

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

@SpringBootApplication
@EnableHystrixDashboard //开启Dashboard
public class DeptConsumerDashboard_9002 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashboard_9002.class,args);
    }

}
           

注意,既然要监控,那么服务端就要有监控相关的依赖,我们看看我的服务端springcloud-provider-dept-8001的依赖中是否有:

Spring Cloud Hystrix 入门

可以看到有。

5.启动9002,访问http://localhost:9002/hystrix

Spring Cloud Hystrix 入门

成功进入监控页面

6.监控服务提供者springcloud-provider-dept-hystrix-9001

(1)在springcloud-provider-dept-hystrix-9001pom文件中导入Hystrix依赖

<!--Hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
           

(2)在springcloud-provider-dept-hystrix-9001启动类中增加一个servlet

package com.wll.springcloud;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;

//启动类
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableDiscoveryClient //使服务发现生效
@EnableCircuitBreaker //添加对熔断的支持
public class DeptProviderHystrix_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_9001.class);
    }

    //增加一个servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}
           

7.启动注册中心,服务提供者和dashboard监控

访问9001端口(localhost:9001/actuator/hystrix.stream):

Spring Cloud Hystrix 入门

接着监控此服务,点击按钮Monitor Stream进行监控

Spring Cloud Hystrix 入门

调用服务提供者(9001端口)的get方法,可看到监控变化。

Spring Cloud Hystrix 入门

图解:

一圈

实心圆:有两种含义,他通过颜色的变化代表了实例的健康程度

它的健康程度从绿色<黄色<橙色<红色递减

该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大,该实心圆就越大,所以通过该实心圆的展示,就可以在大量的实例中快速发现故障实例和高压力实例。

一线

曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势!

Spring Cloud Hystrix 入门

所有springcloud入门相关(建议从上到下依次阅读):

(14条消息) Spring Cloud Eureka 入门_万1999的博客-CSDN博客

(6条消息) Spring Cloud Ribbon 入门_万1999的博客-CSDN博客

(14条消息) Spring Cloud Hystrix 入门_万1999的博客-CSDN博客

(14条消息) Zuul路由网关_万1999的博客-CSDN博客

(14条消息) SpringCloud config分布式配置_万1999的博客-CSDN博客