五、SpringCloud五大神獸之Hystrix
Netflix的創造了一個呼叫的庫Hystrix實現了斷路器圖案。在微服務架構中,通常有多層服務呼叫。
圖1.微服務圖
較低級別的服務中的服務故障可能導致使用者級聯故障。當對特定服務的呼叫達到一定閾值時(Hystrix中的預設值為5秒內的20次故障),電路開啟,不進行通話。在錯誤和開路的情況下,開發人員可以提供後備。
圖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,出現如下介面則監控配置成功