SpringCloud學習筆記(4):Hystrix容錯機制
簡介
在微服務架構中,微服務之間的依賴關係錯綜複雜,難免的某些服務會出現故障,導致服務呼叫方出現遠端排程的執行緒阻塞。在高負載的場景下,如果不做任何處理,可能會引起級聯故障,導致服務呼叫方的資源耗盡甚至整個系統奔潰。Hystrix是一個由Netflix開源的一個延遲和容錯庫,它通過新增延遲容忍和容錯邏輯來幫助控制這些微服務之間的互動。Hystrix通過隔離服務之間的訪問點、停止跨服務的級聯故障並提供回退選項來實現這一點,所有這些選項都提高了系統的總體彈性。
專案介紹
- sc-parent,父模組(請參照SpringCloud學習筆記(1):Eureka註冊中心)
- sc-eureka,註冊中心(請參照SpringCloud學習筆記(1):Eureka註冊中心)
- sc-provider,提供者(請參照SpringCloud學習筆記(1):Eureka註冊中心)
- sc-consumer-hystrix-ribbon,使用Hystrix+Ribbon的消費者
- sc-consumer-hystrix-feign,使用Hystrix+Feign的消費者
在Ribbon上使用Hystrix
1.在父模組下建立子模組專案sc-consumer-hystrix-ribbon,pom.xml:
<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"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.cf</groupId> <artifactId>sc-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>sc-consumer-hystrix-ribbon</artifactId> <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> </project>
2.建立啟動類consumer.ConsumerApplication:
package consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableCircuitBreaker public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } //為RestTemplate整合Ribbon,使其具備負載均衡的能力 @LoadBalanced @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
3.建立呼叫提供者服務的Controller:consumer.controller.ConsumerController
package consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod="getBookListFallBack")
@GetMapping("/getBookList")
public String getBookList(){
return restTemplate.getForObject("http://sc-provider/book/list", String.class);
}
public String getBookListFallBack(){
return "[\"Java入門到放棄\"]";
}
}
@HystrixCommand:表示將getBookList方法作為hystrix命令呼叫的方法。
fallbackMethod:指定處理回退邏輯的方法,這裡是getBookListFallBack方法,當getBookList方法跑出異常時將會呼叫getBookListFallBack方法。
注意:回退方法應該與作為hystrix命令呼叫的方法具有相同的簽名。
4.建立application.yml:
server:
port: 8083
spring:
application:
name: sc-consumer-hystrix-ribbon
eureka:
client:
registerWithEureka: false
serviceUrl:
defaultZone: http://localhost:8080/eureka/
5.測試
依次啟動註冊中心sc-eureka、提供者sc-provider、消費者sc-consumer-hystrix-ribbon,並訪問http://localhost:8083/getBookList,結果顯示如下:
這是提供者正常返回的值,接下來將提供者sc-provider關閉,再次訪問http://localhost:8083/getBookList,結果顯示如下:
因為將提供者sc-provider關閉後,消費者再訪問提供者時會報錯,Hystrix捕獲異常後會直接呼叫回退方法也就是getBookListFallBack方法。
在Feign上使用Hystrix
1.在父模組下建立子模組專案sc-consumer-hystrix-feign,pom.xml:
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cf</groupId>
<artifactId>sc-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>sc-consumer-hystrix-feign</artifactId>
<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-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
</project>
2.建立啟動類feign.FeignApplication:
package feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
3.建立Feign宣告式介面:feign.inter.BookService
package feign.inter;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import feign.fallback.BookFallBack;
@FeignClient(value="sc-provider", fallbackFactory=BookFallBack.class)
public interface BookService {
@GetMapping("/book/list")
public String getBookList();
}
@FeignClient註解中的fallbackFactory屬性是指定的Feign客戶端介面定義回退工廠。
4.建立呼叫提供者服務的Controller:
package feign.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import feign.inter.BookService;
@RequestMapping("/feign")
@RestController
public class FeignController {
@Autowired
private BookService bookService;
@GetMapping("/getBookList")
public String getBookList(){
return bookService.getBookList();
}
}
5.建立application.yml:
server:
port: 8084
spring:
application:
name: sc-consumer-hystrix-feign
eureka:
client:
registerWithEureka: false
serviceUrl:
defaultZone: http://localhost:8080/eureka/
feign:
hystrix:
enabled: true #開啟hystrix支援
6.建立回退工廠類:
package feign.fallback;
import org.springframework.stereotype.Component;
import feign.hystrix.FallbackFactory;
import feign.inter.BookService;
@Component
public class BookFallBack implements FallbackFactory<BookService>{
@Override
public BookService create(Throwable cause) {
return new BookService() {
@Override
public String getBookList() {
return "[\"Java入門到放棄\"]";
}
};
}
}
create方法返回一個回退例項,回退例項為Feign宣告式介面BookService的實現類,提供了與BookService相對應的回退方法,BookService介面呼叫失敗時將會呼叫該實現類中的回退方法。
7.測試:
依次啟動註冊中心sc-eureka、提供者sc-provider、消費者sc-consumer-hystrix-feign,並訪問http://localhost:8084/feign/getBookList,結果顯示如下:
這是提供者正常返回的值,接下來將提供者sc-provider關閉,再次訪問http://localhost:8084/feign/getBookList,結果顯示如下:
8.查看回退原因
修改回退工廠類BookFallBack:
@Component
public class BookFallBack implements FallbackFactory<BookService>{
@Override
public BookService create(Throwable cause) {
return new BookService() {
@Override
public String getBookList() {
//將回退原因輸出到控制檯
cause.printStackTrace(System.out);
return "[\"Java入門到放棄\"]";
}
};
}
}
依次啟動註冊中心sc-eureka、消費者sc-consumer-hystrix-feign,並訪問http://localhost:8084/feign/getBookList,控制檯輸出:
com.netflix.hystrix.exception.HystrixTimeoutException
at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$1.run(AbstractCommand.java:1142)
at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:41)
at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:37)
at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable.run(HystrixContextRunnable.java:57)
at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$2.tick(AbstractCommand.java:1159)
......