最近在工作,本來沒有什麼心情寫Blog的。但是沒有面試也沒有什麼事情可以幹,所以繼續寫吧~
Hystrix 是作爲熔斷的技術,什麼叫熔斷呢?SpringCloud的各個微服務之間是採用通過網絡調用的,網絡充滿各種不穩定性,所以非常容易出現雪崩效應,爲什麼叫雪崩,當A調用了B微服務,B微服務又調用了C微服務,C微服務無法相應,C和B就會一直拉着鏈接等待超時。只要你訪問併發量夠大,很快的連接線程池就會被打滿,這個後果會怎麼樣估計充滿開發經驗的你們應該意識到嚴重性了。C拖住了B,導致B又拖住了A,併發住夠大的話,所有服務都得掛~。
所以本着你掛了別連累我的精神,C微服務掛就讓他掛,別讓B和A服務作爲陪葬品。所以我們的Hystrix主要就是解決這個大難臨頭各自飛的功能。
一、容錯方案
1、網絡請求超時。如果調用的服務的事件過長,最大的可能就可能是微服務的負載出現問題,再去調用將會得不償失,導致多個線程越累越多,最終等到JVM線程池打滿。
2、熔斷模式,這個就是你家裏那個總閘,以前不是有個保險絲嗎?超過複覈就熔斷那個保險絲,保證安全。同樣道理,如果你所調用的微服務在一段時間無法訪問,就正明你所調用的微服務已經跪舔了,所以你再去利用資源調用也是浪費。所以採取熔斷,將所有調用的鏈接的請求先停掉,直接返回錯誤,做到快速失敗。但是熔斷也需要在一段時間後開啓斷路器半開模式,允許部分請求不直接返回錯誤,並嘗試調用服務,從而發現服務是否恢復的檢測。
二、Hystrix實現了什麼?
1、包裹請求,使用HystrixCommand包裹對依賴的調用邏輯。(這個我還是不太理解,不着急等我看完後面2本關於微服務的書,再補充)
2、跳閘機制:調用服務超過錯誤率閾值,Hystrix可以實現手動或者自動跳閘,停止一段時間的服務請求。(這個好理解)
3、資源隔離:Hystrix爲每個依賴都維護了一個小型的線程。如果該線程池已經打滿,直接拒絕訪問。
廢話說完,搞起~
三、Hystrix整合
例牌環境貼出Maven:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
目標容錯點,還是我們的商品服務,在調用的controller當中做容錯:
@HystrixCommand(fallbackMethod = "getProductFallback",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000"), },threadPoolProperties = { @HystrixProperty(name = "coreSize" ,value = "1"), @HystrixProperty(name = "maxQueueSize",value = "10") }) @GetMapping("/getProduct/{productId}/userId/{userId}") public Map<String, Object> getProduct(@PathVariable int productId, @PathVariable int userId) { Map<String, Object> map = new HashMap<>(); String url = "http://tony-mall-provider-user/user/getUserById/" + userId; User user = this.restTemplate.getForEntity(url, User.class).getBody(); Product product = this.productRepository.getByProductId(productId); map.put("user", user); map.put("product", product); return map; } public Map<String,Object> getProductFallback(@PathVariable int productId, @PathVariable int userId){ Map<String, Object> map = new HashMap<>(); User user = new User(); user.setUserId(-1); user.setUsername("ErrorUser"); Product product = this.productRepository.getByProductId(productId); map.put("user", user); map.put("product", product); return map; }解釋一下:
1、 fallback method 當調用失敗(包括熔斷後),使用fallbackmethod指定的方法進行調用和返回(通常指向降級策略)
2、isolation.thread.timeoutInMilliseconds 調用超時限制
3、coresize 核心線程池大小 默認10
4、maxQueueSize 登錄隊列,這裏默認爲不等待直接報錯,這裏是採用BlockingQueue
還有其他的一堆配置,官方文檔有,但是我也沒有看,找到工作之後去看看:
https://github.com/Netflix/Hystrix/wiki/Configuration
四、整合Feign使用Hystrix
SpringCloud 已經幫我們準備最重要的東西 將Hystrix整合到Feign。
其實非常容易看懂,我也沒有介紹的必要了:
@FeignClient(name = "tony-mall-provider-user",fallback = UserFeignClientFallback.class) public interface UserFeignClient { @GetMapping("/user/getUserById/{id}") User getUserById(@PathVariable("id") int id); @PutMapping("/user/add") User addUser(@RequestParam("username") String username, @RequestParam("password")String password,@RequestParam("balance") long balance); }我們在定義FeignClient的地方,聲明fallback並指定到UserFeignClient的一個實現類(注意:UserFeignClientFallback這個類必須要是Spring 的bean)
@Component public class UserFeignClientFallback implements UserFeignClient { @Override public User getUserById(int id) { User user = new User(); user.setBalance(0); user.setUserId(0); user.setUsername("Default"); user.setUserpwd("NULL"); return user; } @Override public User addUser(String username, String password, long balance) { User user = new User(); user.setBalance(0); user.setUserId(0); user.setUsername("Default"); user.setUserpwd("NULL"); return user; } }最後我們還需要在配置類中添加@EnableCircuitBreaker annotation:
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients @EnableCircuitBreaker public class ProductsystemApplication {
除了使用fallback還有一個fallback factory 可以獲得錯誤的exception,根據不同的throwable去進行降級是個不錯的方案;
這裏通過實現FallbackFactory接口的create方法,編寫fallback的方法。
@Component public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient> { @Override public UserFeignClient create(Throwable throwable) { throwable.printStackTrace(); return new UserFeignClient() { @Override public User getUserById(int id) { User user = new User(); user.setBalance(0); user.setUserId(0); user.setUsername("Default"); user.setUserpwd("NULL"); return user; } @Override public User addUser(String username, String password, long balance) { User user = new User(); user.setBalance(0); user.setUserId(0); user.setUsername("Default"); user.setUserpwd("NULL"); return user; } }; } }
然後將FeignClient annotation的配置從fallback 改爲 fallbackFactory 然後指定上面創建的這個類:
@FeignClient(name = "tony-mall-provider-user",fallbackFactory = UserFeignClientFallbackFactory.class) public interface UserFeignClient {
五、Hystrix Dashboard
通過Dashbord 實現對沒有接口的監控
創建一個新的項目,已經添加如下的maven 依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency>然後再配置類當中打上@EnbleHystrixDashboard
@SpringBootApplication @EnableHystrixDashboard public class HystrixdashboardApplication { public static void main(String[] args) { SpringApplication.run(HystrixdashboardApplication.class, args); } }
然後application.properties配置端口,這裏就不貼了。然後運行~
所有整合了hystrix的微服務,都會提供一個hystrix.stream 端點獲得當前hystrix的監控指標。相當全面:
ping: data: {"type":"HystrixCommand","name":"getProduct","group":"ProductController","currentTime":1500476379289,"isCircuitBreakerOpen":false,"errorPercentage":0,"errorCount":0,"requestCount":0,"rollingCountBadRequests":0,"rollingCountCollapsedRequests":0,"rollingCountEmit":0,"rollingCountExceptionsThrown":0,"rollingCountFailure":0,"rollingCountFallbackEmit":0,"rollingCountFallbackFailure":0,"rollingCountFallbackMissing":0,"rollingCountFallbackRejection":0,"rollingCountFallbackSuccess":0,"rollingCountResponsesFromCache":0,"rollingCountSemaphoreRejected":0,"rollingCountShortCircuited":0,"rollingCountSuccess":0,"rollingCountThreadPoolRejected":0,"rollingCountTimeout":0,"currentConcurrentExecutionCount":0,"rollingMaxConcurrentExecutionCount":0,"latencyExecute_mean":5006,"latencyExecute":{"0":5004,"25":5007,"50":5007,"75":5007,"90":5007,"95":5007,"99":5007,"99.5":5007,"100":5007},"latencyTotal_mean":5006,"latencyTotal":{"0":5004,"25":5007,"50":5007,"75":5007,"90":5007,"95":5007,"99":5007,"99.5":5007,"100":5007},"propertyValue_circuitBreakerRequestVolumeThreshold":20,"propertyValue_circuitBreakerSleepWindowInMilliseconds":5000,"propertyValue_circuitBreakerErrorThresholdPercentage":50,"propertyValue_circuitBreakerForceOpen":false,"propertyValue_circuitBreakerForceClosed":false,"propertyValue_circuitBreakerEnabled":true,"propertyValue_executionIsolationStrategy":"THREAD","propertyValue_executionIsolationThreadTimeoutInMilliseconds":5000,"propertyValue_executionTimeoutInMilliseconds":5000,"propertyValue_executionIsolationThreadInterruptOnTimeout":true,"propertyValue_executionIsolationThreadPoolKeyOverride":null,"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"propertyValue_requestCacheEnabled":true,"propertyValue_requestLogEnabled":true,"reportingHosts":1,"threadPool":"ProductController"} data: {"type":"HystrixCommand","name":"UserFeignClient#getUserById(int)","group":"tony-mall-provider-user","currentTime":1500476379296,"isCircuitBreakerOpen":false,"errorPercentage":0,"errorCount":0,"requestCount":0,"rollingCountBadRequests":0,"rollingCountCollapsedRequests":0,"rollingCountEmit":0,"rollingCountExceptionsThrown":0,"rollingCountFailure":0,"rollingCountFallbackEmit":0,"rollingCountFallbackFailure":0,"rollingCountFallbackMissing":0,"rollingCountFallbackRejection":0,"rollingCountFallbackSuccess":0,"rollingCountResponsesFromCache":0,"rollingCountSemaphoreRejected":0,"rollingCountShortCircuited":0,"rollingCountSuccess":0,"rollingCountThreadPoolRejected":0,"rollingCountTimeout":0,"currentConcurrentExecutionCount":0,"rollingMaxConcurrentExecutionCount":0,"latencyExecute_mean":0,"latencyExecute":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"latencyTotal_mean":0,"latencyTotal":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"propertyValue_circuitBreakerRequestVolumeThreshold":20,"propertyValue_circuitBreakerSleepWindowInMilliseconds":5000,"propertyValue_circuitBreakerErrorThresholdPercentage":50,"propertyValue_circuitBreakerForceOpen":false,"propertyValue_circuitBreakerForceClosed":false,"propertyValue_circuitBreakerEnabled":true,"propertyValue_executionIsolationStrategy":"THREAD","propertyValue_executionIsolationThreadTimeoutInMilliseconds":1000,"propertyValue_executionTimeoutInMilliseconds":1000,"propertyValue_executionIsolationThreadInterruptOnTimeout":true,"propertyValue_executionIsolationThreadPoolKeyOverride":null,"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"propertyValue_requestCacheEnabled":true,"propertyValue_requestLogEnabled":true,"reportingHosts":1,"threadPool":"tony-mall-provider-user"} data: {"type":"HystrixThreadPool","name":"tony-mall-provider-user","currentTime":1500476379296,"currentActiveCount":0,"currentCompletedTaskCount":6,"currentCorePoolSize":10,"currentLargestPoolSize":6,"currentMaximumPoolSize":10,"currentPoolSize":6,"currentQueueSize":0,"currentTaskCount":6,"rollingCountThreadsExecuted":0,"rollingMaxActiveThreads":0,"rollingCountCommandRejections":0,"propertyValue_queueSizeRejectionThreshold":5,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"reportingHosts":1} data: {"type":"HystrixThreadPool","name":"ProductController","currentTime":1500476379297,"currentActiveCount":0,"currentCompletedTaskCount":11,"currentCorePoolSize":1,"currentLargestPoolSize":1,"currentMaximumPoolSize":1,"currentPoolSize":1,"currentQueueSize":0,"currentTaskCount":11,"rollingCountThreadsExecuted":0,"rollingMaxActiveThreads":0,"rollingCountCommandRejections":0,"propertyValue_queueSizeRejectionThreshold":5,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"reportingHosts":1}當然看上去是的確有點費勁,這是後我們剛剛搭建好的dashboard就是提供友好的分析界面(其實都唔多友好噶啦~)
訪問我們搭好的dashboard的頁面:http://localhost:7701/hystrix
然後再URL上寫上我們商品服務的hystrix.stream端點->http://localhost:8802/hystrix.stream
好了,現在就有個問題,這麼多個微服務一個個輸入非常麻煩,有沒有一個將所有微服務的hystrix.stream整合起來的東西呢~?有turbine~ 但是我好睏我要睡了~ 有空接着寫~
其實hystrix還有很多東西可以研究,有空繼續挖~ 睡覺~