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