SpringCloud-5-Hystrix

Hystrix

1. Hystrix概述

Netflix的创造了一个调用的库Hystrix实现了断路器图案。在微服务架构中,一般有多层服务调用。java

ia_300000008

当其中有一个系统有延迟, 它会阻塞整个用户请求web

soa-2-640

在高流量的状况下,一个后端依赖项的延迟可能致使全部服务器上的全部资源在数秒内饱和(即服务雪崩)spring

ia_300000010

2. 服务熔断

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

熔断机制的注解是@HystrixCommandapache

1. 添加依赖

咱们是在服务端就行服务熔断的, 所以在provider中进行操做编程

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

2. 编写controller

package com.wang.springcloud.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.wang.springcloud.pojo.Dept;
import com.wang.springcloud.service.DeptService;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
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;

//提供RestFul服务!
@RestController
@ApiModel("Provider Controller")
public class DeptController {

    @Autowired
    private DeptService deptService;

    //注册DiscoveryClient, 注意此时要导入的包是SpringCloud的
    //获取一些配置的信息, 获得具体的微服务
    @Autowired
    private DiscoveryClient client;

    @ApiOperation("经过部门编号得到一个部门的信息")
    @GetMapping("/dept/get/{id}")
    //只要失败, 调用对应的方法
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public Dept get(@PathVariable("id") @ApiParam("部门的id") Long id){
        Dept dept = deptService.queryById(id);

        //若是id不存在, 会返回null, 这里抛出异常
        if (dept == null) {
            throw new RuntimeException("id => " + id + " , 不存在该用户, 或者信息没法找到!");
        }

        return dept;
    }

    //备选方法 ==> 当查询的id不存在, 建立对应id的对象, name字段放入提示信息, 失败时返回咱们建立的对象!
    public Dept hystrixGet(@PathVariable("id") @ApiParam("部门的id") Long id){
        //这里能够用链式编程, 是由于咱们在pojo的lombok中开启了链式编程的支持
        return new Dept()
                .setDeptno(id)
                .setDname("id => " + id + " , 没有对应的信息, null ---- @Hystrix")
                .setDb_source("This database is not exist in Mysql");
    }

    //注册进来的微服务, 得到一些信息(获得配置文件中的info的信息)
    @ApiOperation("微服务的信息")
    @GetMapping("/dept/discovery")
    public Object discovery() {
        //获取微服务列表的清单
        List<String> services = client.getServices();
        System.out.println("discovery => services: " + services);

        //获得一个具体的微服务, 经过具体的微服务ID, applicationName(即为在配置文件中配置的该SpringBoot的名字!)
        List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");

        for (ServiceInstance instance : instances) {
            System.out.println(
                    instance.getHost() + "\t" +
                    instance.getPort() + "\t" +
                    instance.getUri() + "\t" +
                    instance.getServiceId()
            );
        }

        //返回这个client就能够了
        return this.client;
    }

}

注意后端

  • 使用 @HystrixCommand 注解, 并用 fallbackMethod 属性指定服务熔断后调用的方法(此处即抛出异常 ==> 不熔断的话显示为500)服务器

  • 熔断调用的方法中, 并用写Mapping的注解, 和调用该方法的服务用同一个url架构

  • 能够将错误信息返回到对象中app

3. 在主启动类中声明

package com.wang.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
//在服务启动后自动将该服务注册到Eureka中
@EnableEurekaClient
//服务发现, 这样就能够监控了
@EnableDiscoveryClient
//添加对熔断的支持(启用断路器)
@EnableCircuitBreaker
public class DeptProviderHystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_8001.class, args);
    }
}

注意

  • 此处服务熔断要添加的是熔断器的支持 @EnableCircuitBreaker

4. Eureka中的小技巧(没什么用)

能够显示服务的IP地址(最后一行设置为true)

#Eureka配置, 配置该服务注册到哪里(与Server中的url地址一致)
eureka:
  client:
    service-url:
      #向集群发布, 只须要向全部的Eureka发布url就能够了
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept-hystrix-8001  #修改Eureka上的默认描述信息
    prefer-ip-address: true

效果以下

image-20201012155743688

3. 服务降级

服务降级是发生在客户端上的, 并且依附于feign, 咱们在使用了feign的consumer上设置

1. 编写降级的工厂类

咱们在API中写降级的工厂类, 从而能够被其余模块调用到

package com.wang.springcloud.service;

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

import java.util.List;

//降级
@Component
public class DeptClientFallbackFactory 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 null;
            }
        };
    }
}

注意

  • 要注册到SpringBoot中
  • 想要实现服务降级, 要实现FallbackFactory接口, 并重写方法
  • 重写方法的类型能够换成咱们须要的类型(原来是Object, 支持全部的类型)
  • 若是咱们使用的类型为接口, 要在返回值中实现该接口

2. 开启服务降级的支持

开启服务降级, 只须要在对应的客户端的配置文件中启用便可

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

4. 服务熔断与服务降级的对比

服务熔断

  • 服务端
  • 某个服务超时或异常, 引发服务熔断, 至关于保险丝

服务降级

  • 客户端
  • 从网站总体的请求负载考虑, 当某个服务熔断或者关闭以后, 服务将再也不被调用, 此时在客户端咱们能够准备一个 FallbackFactory, 返回一个默认的值(缺省值), 总体的服务水平降低了, 比直接挂掉强

相同点

  • 目的很一致,都是从可用性可靠性着想,为防止系统的总体缓慢甚至崩溃,采用的技术手段;

  • 最终表现相似,对于二者来讲,最终让用户体验到的是某些功能暂时不可达或不可用;

  • 粒度通常都是服务级别,固然,业界也有很多更细粒度的作法,好比作到数据持久层(容许查询,不容许增删改);

  • 自治性要求很高,熔断模式通常都是服务基于策略的自动触发,降级虽然说可人工干预,但在微服务架构下,彻底靠人显然不可能,开关预置、配置中心都是必要手段;

不一样点

  • 触发缘由不太同样,服务熔断通常是某个服务(下游服务)故障引发,而服务降级通常是从总体负荷考虑;

  • 管理目标的层次不太同样,熔断实际上是一个框架级的处理,每一个微服务都须要(无层级之分),而降级通常须要对业务有层级之分(好比降级通常是从最外围服务开始)

5. Hystrix Dashboard流量监控

Hystrix提供了一个可视化的流量监控

1. Dashboard的编写

1. 导入依赖

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

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

    <!--实体类以及Web-->
    <dependencies>
        <dependency>
            <groupId>com.wang</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>
        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
        </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>
        <!--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>
    </dependencies>


</project>

注意

  • 此监控是在客户端的, 所以与被监控的客户端的依赖基本相同, 区别是要多配置一个 hystrix-dashboard

2. 编写配置文件

server:
  port: 9002

注意

  • 这里配置好端口号就行了, 注意配置的端口是空闲的端口

3. 配置主启动类

package com.wang.springcloud;

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

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

注意

  • 在主启动类使用注解 @EnableHystrixDashboard 来开启Hystrix Dashboard

2. 被监控的微服务的编写

1. 前提

注意, 微服务被Hystrix Dashboard监控须要知足如下两点

  • 添加了Hystrix依赖
  • 添加了actuator依赖

2. 在主启动类配置Servlet

因为Hystrix Dashboard要求微服务注册一个URL地址, 咱们在SpringBoot中使用 ServletRegistrationBean 类型来注册一个Servlet的Bean

package com.wang.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
//在服务启动后自动将该服务注册到Eureka中
@EnableEurekaClient
//服务发现, 这样就能够监控了
@EnableDiscoveryClient
//添加对熔断的支持(启用断路器)
@EnableCircuitBreaker
public class DeptProviderHystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_8001.class, args);
    }

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

注意

  • 这里写的URLMapping就是咱们在DashBoard中监控的地址的后缀, 前面为localhost: 端口号
  • 这里是固定的写法!

3. Hystrix Dashboard

启动Eureka, Provider和DashBoard, 访问dashboard下的 /hystrix, 输入微服务的URL便可查看

image-20201012222112219

本站公众号
   欢迎关注本站公众号,获取更多信息