1. 程式人生 > >五、SpringCloud五大神獸之Hystrix

五、SpringCloud五大神獸之Hystrix

    Netflix的創造了一個呼叫的庫Hystrix實現了斷路器圖案。在微服務架構中,通常有多層服務呼叫。

HystrixGraph

圖1.微服務圖

較低級別的服務中的服務故障可能導致使用者級聯故障。當對特定服務的呼叫達到一定閾值時(Hystrix中的預設值為5秒內的20次故障),電路開啟,不進行通話。在錯誤和開路的情況下,開發人員可以提供後備。

HystrixFallback

圖2. Hystrix回退防止級聯故障

開放式電路會停止級聯故障,並允許不必要的或失敗的服務時間來癒合。回退可以是另一個Hystrix保護的呼叫,靜態資料或一個正常的空值。回退可能被連結,所以第一個回退使得一些其他業務電話又回到靜態資料

如何使用?

一、服務熔斷

根據之前的8001、8002、8003新建個模組

1、pom

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

    <artifactId>microservisecloud-provider-dept-8001-hystrix</artifactId>

    <name>microservisecloud-provider-dept-8001-hystrix</name>


    <dependencies>
        <!-- 引入自己定義的api通用包,可以使用Dept部門Entity -->
        <dependency>
            <groupId>com.zhanghf</groupId>
            <artifactId>microservisecloud-api</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
        <!-- actuator監控資訊完善 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- 將微服務provider側註冊進eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!-- 修改後立即生效,熱部署 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

    </dependencies>


</project>

2.application.yml配置檔案

server:
  port: 8001

mybatis:
  config-location: classpath:mybatis/mybatis.xml        # mybatis配置檔案所在路徑
  type-aliases-package: com.zhanghf.springcloud.entities    # 所有Entity別名類所在包
  mapper-locations: classpath:mybatis/mapper/**/*.xml                       # mapper對映檔案

spring:
   application:
    name: microservicecloud-dept
   datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 當前資料來源操作型別
    driver-class-name: org.gjt.mm.mysql.Driver              # mysql驅動包
    url: jdbc:mysql://localhost:3306/clouddb01              # 資料庫名稱
    username: root
    password:
    dbcp2:
      min-idle: 5                                           # 資料庫連線池的最小維持連線數
      initial-size: 5                                       # 初始化連線數
      max-total: 5                                          # 最大連線數
      max-wait-millis: 200                                  # 等待連接獲取的最大超時時間

eureka:
  client: #客戶端註冊進eureka服務列表內
    service-url:
#      defaultZone: http://localhost:7001/eureka  單機
       defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  #叢集
#在eureka介面使微服務提供者顯示更直觀:顯示名稱和ip
  instance:
    instance-id: microservicecloud-dept8001-histrix  #改成具有熔斷的8001服務提供者
    prefer-ip-address: true     #訪問路徑可以顯示IP地址

#eureka伺服器中註冊的服務的info頁面的顯示內容
info:
  app.name: microservicecloud
  company.name: www.zhanghf.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$

3、controller裡面和之前的8001、8002、8003的區別是加入了 @HystrixCommand(fallbackMethod = "processHystrix"),即該註解的方法報錯後會執行fallbackMethod裡面的方法,防止服務由於單個業務功能出錯導致雪崩效應

package com.zhanghf.springcloud.controller;


import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.zhanghf.springcloud.entities.Dept;
import com.zhanghf.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DeptController
{
	@Autowired
	private DeptService service;

	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	@HystrixCommand(fallbackMethod = "processHystrix")//一旦呼叫服務方法失敗並丟擲了錯誤資訊後,會自動呼叫@HystrixCommand標註好的fallbackMethod呼叫類中的指定方法
	public Dept get(@PathVariable("id") Long id)
	{
		Dept dept = service.get(id);
		if(null == dept){
			throw new RuntimeException("該ID:"+id+"沒有對應資訊");
		}
		return dept;
	}

	//熔斷後執行的方法
	public Dept processHystrix(@PathVariable("id") Long id)
	{
		return new Dept().setDeptno(id).setDname("該ID:" + id + "沒有沒有對應的資訊,[email protected]")
				.setDb_source("no this database in MySQL");

	}

}

 上述例子是賊get方法中如果查不到對應的部門則報錯,根據熔斷機制,報錯後會執行processHystrix方法。

4、啟動類的區別是加入熔斷支援的註解@EnableCircuitBreaker

5、測試

分別啟動7001、7002、7003和帶熔斷支援的8001。資料庫中部門有5個,因此訪問id為1到5都正常,訪問http://localhost:8001/dept/get/55則無法查出部門資訊,觸發熔斷機制:

二、服務降級

服務降級,簡單地理解就是其中一個服務的資源快不夠了,忍痛將某些服務先關掉,待渡過難關,再開啟回來。

該操作執行在微服務客戶端的消費者上,依託於之前帶feign的80服務,服務提供者是否支援服務熔斷的8001都可以

1、pom

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

    <artifactId>microservisecloud-consumer-dept-feign</artifactId>


    <dependencies>
        <!-- 引入自己定義的api通用包,可以使用Dept部門Entity -->
        <dependency>
            <groupId>com.zhanghf</groupId>
            <artifactId>microservisecloud-api</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--feign相關-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <!-- Ribbon相關  Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具。-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <!--Ribbon相關end-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 修改後立即生效,熱部署 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

2、application.yml配置檔案開啟服務降級支援

feign:
  hystrix:
    enabled: true

3、在feign講解一篇中的api模組的DeptClientService介面那個包下編寫類FallbackDeptClientService,實現介面FallbackFactory,接口裡面實現DeptClientService類,在過載方法裡面返回DeptClientService物件,裡面根據相應的方法執行相應的降級操作。最後用@Commonnet註解標註這個類

package com.zhanghf.springcloud.service;

import com.zhanghf.springcloud.entities.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.List;

/**
 * 用途:服務降級
 */
@Component
public class FallbackDeptClientService implements FallbackFactory<DeptClientService> {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept get(@PathVariable("id") long id) {
                 return new Dept().setDeptno(id).setDname("該ID:" + id + "沒有沒有對應的資訊,Consumer客戶端提供的降級資訊,此刻服務Provider已經關閉")
                        .setDb_source("no this database in MySQL");
            }

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

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

4、在DeptClientService介面的@FeignClient註解裡面新增fallbackFactory

package com.zhanghf.springcloud.service;

import com.zhanghf.springcloud.entities.Dept;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

/**
 * @Description: 修改microservicecloud-api工程,根據已經有的DeptClientService介面
 * Created by YQ11053 on 2018/10/5 0005.
 */
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory = FallbackDeptClientService.class)
public interface DeptClientService {

    @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
    public Dept get(@PathVariable("id") long id);

    @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
    public List<Dept> list();

    @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
    public boolean add(Dept dept);
}

5、測試

分別啟動7001、7002、7003、8001、帶feign的8080

 三、服務監控

1、pom

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

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


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 自己定義的api -->
        <dependency>
            <groupId>com.zhanghf</groupId>
            <artifactId>microservisecloud-api</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 修改後立即生效,熱部署 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!-- Ribbon相關 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!-- feign相關 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <!-- hystrix和 hystrix-dashboard相關 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

2、配置檔案application.yml

server:
  port: 9001

3、啟動類添加註解@EnableHystrixDashboard

package com.zhanghf;

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

/**
 * HystrixDashboard監控,在監控的服務中記得新增actuator的pom配置
 *
 */
@SpringBootApplication
@EnableHystrixDashboard
public class DeptConsumer_DashBoard_App
{
    public static void main( String[] args )
    {
        SpringApplication.run(DeptConsumer_DashBoard_App.class,args);
    }
    
}

4、分別啟動7001、7002、7003、帶hyxtrix的8001、訪問9001http://localhost:9001/hystrix,出現如下介面則監控配置成功