SpringBoot學習8.6-hystrix微服務訪問熔斷

概要

本文是以SpringBoot學習8.5-feign負載均衡調用微服務爲基礎的。

hystrix:springcloud提供的微服務訪問熔斷和降級組件。

當微服務相應變慢,可能瞬間堆積很多請求,導致其他微服務或請求端的請求積壓,可能導致系統癱瘓。這時候需要將這些超時或者無法處理的請求釋放出去(熔斷、降級),避免系統癱瘓,hystrix可以解決上述問題。

開發要點:

  • 依賴hystrix
  • spring斷路器配置
  • @EnableCircuitBreaker開啓斷路器
  • @HystrixCommand設置降級方法

1.maven依賴

熔斷機制主要依賴hystrix(當然負載均衡的需要的ribbon、feign也是必須的)。

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.0.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
 
......
 
<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
	<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
 
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	<!-- 實現負載均衡的ribbon依賴包 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
	</dependency>
	<!-- 實現負載均衡的feign依賴包 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>
	<!-- 斷路器 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	</dependency>
</dependency>
 
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

2.spring配置

關注其中的斷路器配置

server:
  port: 8001 # 服務器端口

spring:
  application:
    name: app-server # 微服務名稱
  mvc: #定義視圖解析器的規則
    view:
      prefix: classpath:/templates/ #文件前綴,templates是thymeleafd的默認路徑
      suffix: .html #文件後綴

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:7001/eureka/ # 治理客戶端服務域
      
ribbon:
  OkToRetryOnAllOperations: false #對所有操作請求都進行重試,默認false
  ReadTimeout: 2000   #負載均衡超時時間,默認值5000  # 超過則會斷路
  ConnectTimeout: 1000 #ribbon請求連接的超時時間,默認值2000
  MaxAutoRetries: 0     #對當前實例的重試次數,默認0
  MaxAutoRetriesNextServer: 1 #對切換實例的重試次數,默認1
    
# 斷路器
hystrix:
  command:
    default:  #default全局有效,service id指定應用有效
      execution:
        timeout:
          enabled: true #如果enabled設置爲false,則請求超時交給ribbon控制,爲true,則超時作爲熔斷根據
        isolation:
          thread:
            timeoutInMilliseconds: 1000 #斷路器超時時間,默認1000ms # 注意:與ribbon.ReadTimeout誰小誰生效            

3.開發斷路器

@EnableCircuitBreaker開啓斷路器:

import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCircuitBreaker // 開啓斷路器
public class CircuitBreakerConfig {
}

@HystrixCommand斷路器設置降級方法(斷路時來處理請求的方法)、單個方法的超時時間設置。

spring配置中設定了全局超時時間。

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
@Controller
@RequestMapping("/product")
@ResponseBody
public class ProductController {
	@Autowired
	private ProductService productService;

	@RequestMapping("/getById/{id}")
	@HystrixCommand(fallbackMethod = "errorGetById", // 斷路器-降級處理(默認超時時間1000ms,超時則調用fallbackMethod方法)
			commandProperties = {
					@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") }) // 設置超時時間
	public Product getById(@PathVariable String id) {
		// 調用微服務
		Product product = productService.getById(id);
		return product;
	}
	// 斷路器-降級處理方法
	public Product errorGetById(String id) {
		System.out.println("主鍵查詢連接超時!");
		return new Product("", "主鍵查詢連接超時!");
	}
}

4.測試

微服務端代碼:

其中取2000以內的隨機數作爲線程休眠時間,製造超時現象。

@RestController
@RequestMapping("/productRestController")
public class ProductRestController {
	@GetMapping("/product/{id}")
	public Product getProduct(@PathVariable String id) throws InterruptedException {
		Long ms = (long) (2000L*Math.random());// 隨機數,2000之內
		System.out.println(ms);
		Thread.sleep(ms);
		return new Product(id, "產品" + id);
	}
}

4.1.測試a

注意:ribbon.ReadTimeout: 2000,hystrix的timeoutInMilliseconds:1000

微服務打印的睡眠時間(我們認爲是服務端的相應時間),請求端的日誌:

爲什麼超過1000ms時請求端會打印成功日誌?

現象:熔斷了的話降級方法內的日誌輸出,但是原方法內的日誌也輸出了,說明了原方法的邏輯在微服務響應後繼續執行(這還是我的猜想),而前臺會獲得降級方法的返回結果。

因爲微服務調用的響應時間是ribbon.ReadTimeout: 2000,上述時間均未超過2000

下面的實驗驗證上述說法。

4.1.測試b

修改ribbon.ReadTimeout: 1000,hystrix的timeoutInMilliseconds不變。

現象:熔斷了的話降級方法內的日誌輸出,原方法內的日誌不輸出了,說明了原方法的邏輯在超時的情況沒執行,前臺會獲得降級方法的返回結果。

綜上兩種測試情況,我理解爲:

  • 超過ribbon.ReadTimeout響應時間,則請求端方法在沒有獲得微服務響應的情況下後續邏輯不執行了。
  • 超過hystrix的timeoutInMilliseconds則熔斷且調用降級方法。原方法的邏輯不歸我管理。

 

github:https://github.com/zhangyangfei/spring-cloud-learn.git 中的cloud-parent工程。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章