1. 程式人生 > >Spring Cloud Feign 中使用Hystrix進行請求降級和快速失敗

Spring Cloud Feign 中使用Hystrix進行請求降級和快速失敗

前言

微服務中經常會用到熔斷器來增強服務依賴的穩定性,他可以在網路連線緩慢,資源繁忙,暫時不可用,服務離線等情況中進行服務的快速失敗,並可自我恢復,以避免請求執行緒的堆積造成大量資源的浪費。

相信讀者看這篇文章的目的都是解決實際問題,並不是來看我分析原始碼的,如果對原始碼感興趣的我推薦《重新定義》,所以我們直接上乾貨,下面我們就簡單的利用Feign中整合的Hystrix進行快速失敗和請求降級處理。

正文

首先準備一個父專案,裡面只有各個服務所需的依賴包,下面就是父專案的pom,可以看到我這次演練的專案有三個,分別是eureka-server,consumer-service,provider-service

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.3.RELEASE</version>
	</parent>

	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.springcloud.book</groupId>
	<artifactId>ch6-2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>

	<modules>
		<module>ch6-2-eureka-server</module>
		<module>ch6-2-consumer-service</module>
		<module>ch6-2-provider-service</module>
	</modules>

	<!-- 管理依賴 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.RELEASE</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>



	<!--注意: 這裡必須要新增, 否者各種依賴有問題 -->
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/libs-milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

下面建立eureka-server服務

下面依次是pom,yml,和啟動類的程式碼,這裡不做解釋了,前幾個部落格已經介紹過類似的內容。

<parent>
		<groupId>cn.springcloud.book</groupId>
		<artifactId>ch6-2</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>ch6-2-eureka-server</artifactId>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

接下來建立一個被feign呼叫的服務:provider-service。

這裡很簡單,就是定一個請求地址,用來對映到feign介面上的URl。

下面程式碼依次是provider-service中的controller、啟動類、pom、yml

這裡其實重點就是利用了spring-cloud-starter-netflix-hystrix,別的都沒什麼可解釋的。

@RestController
public class TestController {

	@RequestMapping(value = "/getUser",method = RequestMethod.GET)
	public String getUser(@RequestParam("username") String username){
		return "This is real user";
	}
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
	
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}
<parent>
    <groupId>cn.springcloud.book</groupId>
    <artifactId>ch6-2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <artifactId>ch6-2-provider-service</artifactId>
  
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

最後建立一個consumer-service工程,這裡的程式碼相對上兩個服務要多一些,不過我會按照一定的順序給大家展示,

首先是controller、Feign介面,Feign的快速返回/降級方法、pom、yml,一共五塊程式碼

@RestController
public class TestController {

	@Autowired
	private IUserService userService;
	
	@RequestMapping(value = "/getUser",method = RequestMethod.GET)
	public String getUser(@RequestParam("username") String username) throws Exception{
		return userService.getUser(username);
	}
@FeignClient(name = "sc-provider-service", fallback = UserServiceFallback.class)
public interface IUserService {
	
	@RequestMapping(value = "/getUser",method = RequestMethod.GET)
    String getUser(@RequestParam("username") String username);
    
}
@Component
public class UserServiceFallback implements IUserService{
	/**
	  * 出錯則呼叫該方法返回友好錯誤
	  * @param username
	  * @return
	  */
	public String getUser(String username){
		return "The user does not exist in this system, please confirm username";
	}
}
<parent>
    <groupId>cn.springcloud.book</groupId>
    <artifactId>ch6-2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <artifactId>ch6-2-consumer-service</artifactId>
  
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
server:
  port: 8888
spring:
  application:
    name: sc-consumer-service
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true

好了,五塊程式碼貼上完畢,下面是對上面程式碼的解釋,

首先controller是我們對外暴露的請求入口,呼叫了當前服務的Feign介面,重點是這句話@FeignClient(name = "sc-provider-service", fallback = UserServiceFallback.class),name引數代表請求對映的服務spring. application.name,fallback引數指定的是一個類,這個類必須要實現當前的Feign接口才可以,用於feign呼叫sc-provider-service服務時失敗的快速返回類。然後就是UserServiceFallback類一定注入spring容器。

同樣,這個工程也需要spring-cloud-starter-netflix-hystrix 依賴,另外這裡我用了openfeign你可以理解為feign的升級版。

還有一點需要注意的是高版本中feign的hystrix是預設關閉的,所有我們要手動開啟

 

三個服務分別啟動,首先eureka-service先啟動。

我們可以看到消費者工程和生產者工程分別註冊上了eureka,我們訪問http://localhost:8888/getUser?username=1

可以看到通過feign訪問到了provider-service工程的controller方法了,

下面我們把provider-service工程手動關閉,同樣訪問http://localhost:8888/getUser?username=1,當然是訪問不到的了,但是返回

 我們知道這句話是我fallback引數指定類的方法返回的,

這樣一個簡單的利用feign 整合的熔斷器實現快速返回的例子。

注:對本文有異議或不明白的地方微信探討,wx:15524579896