六、服務容錯保護(Hystrix服務降級)
1、簡介
在微服務架構中,我們將系統拆分成立一個個的服務單元,各單元應用間通過服務註冊與訂閱的方式互相依賴。由於每個單元都在不同的程序間執行,依賴通過遠端呼叫的方式執行,這樣就可以因為網路原因或者依賴服務自身問題出現呼叫故障或延遲,若此時呼叫方的請求不斷增加,最後就會出現因等待出現故障的依賴方響應而形成任務的積壓,執行緒資源無法釋放,最終導致自身服務的癱瘓,進一步甚至出現故障的蔓延導致整個系統的癱瘓。如果這樣的架構存在如此嚴重的隱患,那麼相較於傳統的架構就會更加的不穩定。為了解決這樣的問題,就產生了斷路器等一系列的服務保護機制。針對上述問題,在Spring Cloud Hystrix中實現了執行緒隔離、斷路器等一系列的服務保護功能。它也是基於Netflix的開源框架 Hystrix實現的,該框架目標在於通過控制那些訪問遠端系統、服務和第三方庫的節點,從而對延遲和故障提供更強大的容錯能力。Hystrix具備了服務降級、服務熔斷、執行緒隔離、請求快取、請求合併以及服務監控等強大功能。
建立工程
在之前建立的microservice-spring-cloud工程下,新建一個Moudle,命名為microservice-consumer-movie-ribbon-with-hystrix。然後我們在pom.xml中,引入如下的座標
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
</dependencies>
程式碼部分
User實體類(和之前的一樣)
package zhuangxp.entity; import java.io.Serializable; import java.math.BigDecimal; public class User implements Serializable { private Long id; private String username; private String name; private short age; private BigDecimal balance; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getName() { return name; } public void setName(String name) { this.name = name; } public short getAge() { return age; } public void setAge(short age) { this.age = age; } public BigDecimal getBalance() { return balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } }
MovieController
package zhuangxp.controller; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import zhuangxp.entity.User; @RestController public class MovieController { @Autowired private RestTemplate restTemplate; @GetMapping("/movie/{id}") @HystrixCommand(fallbackMethod = "findByIdFallback") public User getById(@PathVariable("id") Long id){ return this.restTemplate.getForObject("http://microservice-provider-user/getUser/"+id,User.class); } public User findByIdFallback(Long id) { User user = new User(); user.setId(0L); return user; } }
和之前的MovieController不同的是,我們在具體執行邏輯的方法上增加了@HystrixCommand(fallbackMethod = "findByIdFallback")註解來指定服務降級的方法,然後編寫降級的方法,這個方法的引數和返回值應該和原方法保持一致。
啟動類
@SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker public class MainAppConsumerRibbonWithHystrix { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(MainAppConsumerRibbonWithHystrix.class, args); } }
啟動類中使用@EnableCircuitBreaker來開啟Hystrix的使用。
測試驗證
啟動microservice-discovery-eureka、microservice-provider-user、microservice-consumer-movie-ribbon-with-hystrix。訪問MovieController中的getById方法,路徑http://localhost:3001/movie/1,可以正常返回到資料,如下
{"id":1,"username":"user1","name":"張三","age":18,"balance":100.00}
當我們的服務提供者掛掉後(方便演示,手動給停掉),就會訪問到降級的方法,返回值如下:
{"id":0,"username":null,"name":null,"age":0,"balance":null}