Spring Cloud構建微服務架構(三)斷路器
舉個例子,在一個電商網站中,我們可能會將系統拆分成,使用者、訂單、庫存、積分、評論等一系列的服務單元。使用者建立一個訂單的時候,在呼叫訂單服務建立訂單的時候,會向庫存服務來請求出貨(判斷是否有足夠庫存來出貨)。此時若庫存服務因網路原因無法被訪問到,導致建立訂單服務的執行緒進入等待庫存申請服務的響應,在漫長的等待之後使用者會因為請求庫存失敗而得到建立訂單失敗的結果。如果在高併發情況之下,因這些等待執行緒在等待庫存服務的響應而未能釋放,使得後續到來的建立訂單請求被阻塞,最終導致訂單服務也不可用。
在微服務架構中,存在著那麼多的服務單元,若一個單元出現故障,就會因依賴關係形成故障蔓延,最終導致整個系統的癱瘓,這樣的架構相較傳統架構就更加的不穩定。為了解決這樣的問題,因此產生了斷路器模式。
什麼是斷路器
斷路器模式源於Martin Fowler的Circuit Breaker一文。“斷路器”本身是一種開關裝置,用於在電路上保護線路過載,當線路中有電器發生短路時,“斷路器”能夠及時的切斷故障電路,防止發生過載、發熱、甚至起火等嚴重後果。
在分散式架構中,斷路器模式的作用也是類似的,當某個服務單元發生故障(類似用電器發生短路)之後,通過斷路器的故障監控(類似熔斷保險絲),向呼叫方返回一個錯誤響應,而不是長時間的等待。這樣就不會使得執行緒因呼叫故障服務被長時間佔用不釋放,避免了故障在分散式系統中的蔓延。
Netflix Hystrix
下面我們來看看如何使用Hystrix。
準備工作
在開始加入斷路器之前,我們先拿之前構建兩個微服務為基礎進行下面的操作,主要使用下面幾個工程:
-
chapter9-1-1
- eureka-server工程:服務註冊中心,埠1111
- compute-service工程:服務單元,埠2222
-
chapter9-1-2
- eureka-ribbon:通過ribbon實現的服務單元,依賴compute-service的服務,埠3333
- eureka-feign:通過feign實現的服務單元,依賴compute-service的服務,埠3333
若您還沒有使用Spring Cloud的經驗,可以先閱讀《服務註冊與發現》與《服務消費者》,對Spring Cloud構建的微服務有一個初步的認識。
Ribbon中引入Hystrix
- 依次啟動eureka-server、compute-service、eureka-ribbon工程
- 訪問http://localhost:3333/add,呼叫eureka-ribbon的服務,該服務會去呼叫compute-service的服務,計算出10+20的值,頁面顯示30
1234567 | Whitelabel Error PageThis application has no explicit mapping for /error, so you are seeing this as a fallback.Sat Jun 25 21:16:59 CST 2016There was an unexpected error (type=Internal Server Error, status=500).I/O error on GET request for "http://COMPUTE-SERVICE/add?a=10&b=20": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect |
-
pom.xml
中引入依賴hystrix依賴
1234 | <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId></dependency> |
-
在eureka-ribbon的主類
RibbonApplication
中使用@EnableCircuitBreaker
註解開啟斷路器功能:
12345678910111213141516 | public class RibbonApplication { RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonApplication.class, args); }} |
-
改造原來的服務消費方式,新增
ComputeService
類,在使用ribbon消費服務的函式上增加@HystrixCommand
註解來指定回撥方法。
12345678910111213141516 | public class ComputeService { RestTemplate restTemplate; (fallbackMethod = "addServiceFallback") public String addService() { return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody(); } public String addServiceFallback() { return "error"; }} |
- 提供rest介面的Controller改為呼叫ComputeService的addService
123456789101112 | public class ConsumerController { private ComputeService computeService; (value = "/add", method = RequestMethod.GET) public String add() { return computeService.addService(); }} |
- 驗證斷路器的回撥
更多關於Hystrix的使用可參考How To Use
Feign使用Hystrix
注意這裡說的是“使用”,沒有錯,我們不需要在Feigh工程中引入Hystix,Feign中已經依賴了Hystrix,我們可以在未做任何改造前,嘗試下面你的操作:
- 依次啟動eureka-server、compute-service、eureka-feign工程
- 訪問http://localhost:3333/add,呼叫eureka-feign的服務,該服務會去呼叫compute-service的服務,計算出10+20的值,頁面顯示30
1234567 | Whitelabel Error PageThis application has no explicit mapping for /error, so you are seeing this as a fallback.Sat Jun 25 22:10:05 CST 2016There was an unexpected error (type=Internal Server Error, status=500).add timed-out and no fallback available. |
如果您夠仔細,會發現與在ribbon中的報錯是不同的,看到add
timed-out and no fallback available
這句,或許您已經猜到什麼,看看我們的控制檯,可以看到報錯資訊來自hystrix-core-1.5.2.jar
,所以在這個工程中,我們要學習的就是如何使用Feign中整合的Hystrix。
-
使用
@FeignClient
註解中的fallback屬性指定回撥類
1234567 | "compute-service", fallback = ComputeClientHystrix.class)public interface ComputeClient { (method = RequestMethod.GET, value = "/add") Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);} | (value =
-
建立回撥類
ComputeClientHystrix
,實現@FeignClient
的介面,此時實現的方法就是對應@FeignClient
介面中對映的fallback函式。
123456789 | public class ComputeClientHystrix implements ComputeClient { public Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b) { return -9999; }} |
- 再用之前的方法驗證一下,是否在compute-service服務不可用的情況下,頁面返回了-9999。
關於Feign的更多使用方法可參考:Feign