一、在分佈式系統中,服務與服務之間的依賴錯綜複雜,一種不可避免的情況就是某些服務會出現故障,導致依賴於它們的其他服務出現遠程調度的線程阻塞 Hystrix是Netflix 公司開源的一個項目,它提供了熔斷器功能,能夠阻止分佈式系統中出現聯動故障 Hystrix 是通過隔離服務的訪問點阻止聯動故障的,並提供了故障的解決方案,從而提高了整個分佈式系統的彈性。
二、Hystrix的產生:
在複雜的分佈式系統中,可能有幾十個服務相互依賴,這些服務由於某些原因,例如機房的不可靠性、網絡服務商的不可靠性,導致某個服務不可用。如果系統不隔離該不可用的服務,可能會導致整個系統不可用。
對於依賴 30 個服務的應用程序,每個服務的正常運行時間爲 99.99% ,對於單個服務來說, 99.99% 的可用是非常完美的。有99.99^30 = 99.7% 的可正常運行時間和 0.3% 的不可用時間,那麼 10 億次請求中有 3000000次失敗,實際的情況可能比這更糟糕。
如果不設計整個系統的韌性,即使所有依賴關係表現良好,單個服務只有 0.01% 的不可用,由於整個系統的服務相互依賴,最終對整個系統的影響是非常大的。
在上圖中一個用戶需要請求A、H、I、P。如果中間I服務網絡延遲或者發生故障,即A、H、P不可用。在高併發的情況下,單個服務的延遲會導致整個請求都處於延遲狀態,可能在幾秒鐘就使整個服務處於線程負載飽和的狀態。
某個服務的單個點的請求故障會導致用戶的請求處於阻塞狀態,最終的結果就是整個服務的線程資源消耗殆盡。由於服務的依賴性,會導致依賴於該故障服務的其他服務也處於線程阻塞狀態,最終導致這些服務的線程資源消耗殆盡 直到不可用,從而導致整個問服務系統都不可用,即雪崩效應。
爲了防止雪崩效應,因而產生了熔斷器模型。 Hystrix 是在業界表現非常好的 個熔斷器模型實現的開源組件,它是 Spring Cloud 組件不可缺少的一部分。
三、Hystrix的設計原則:
1)防止單個服務的故障耗盡整個服務的 Servlet 容器(例如 Tomcat )的線程資源。
2)快速失敗機制,如果某個服務出現了故障,則調用該服務的請求快速失敗,而不是線程等待。
3)提供回退( fallback )方案,在請求發生故障時,提供設定好的回退方案。
4)使用熔斷機制,防止故障擴散到其他服務。
5)提供熔斷器的監控組件 Hystrix Dashboard ,可以實時監控熔斷器的狀態。
四、Hystrix的工作機制:
首先,當服務的某個 API 接口的失敗次數在一定時間內小於設定的閥值時,熔斷器處於關閉狀態,該 API 接口正常提供服務 。當該API 接口處理請求的失敗次數大於設定的閥值時, Hystrix 判定該 API 接口出現了故障,打開熔斷器,這時請求該 API 接口會執行快速失敗的邏輯(即 fall back 回退的邏輯),不執行業務邏輯,請求的線程不會處於阻塞狀態。處於打開狀態的熔斷器,一段時間後會處於半打開狀態,並將一定數量的請求執行正常邏輯。剩餘的請求會執行快速失敗,若執行正常邏輯的請求失敗了,則熔斷器繼續打開。若成功了 ,則將熔斷器關閉。這樣熔斷器就具有了自我修復的能力。
五、服務中對Hystrix的基本使用
1)Ribbon中使用Hystrix熔斷器(我們基於前面的Spring-Cloud之Ribbon負載均衡-3代碼進行改造)。
a、加入依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
b、加入註解(@EnableHystrix)開啓熔斷器功能
package com.cetc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; @SpringBootApplication @EnableEurekaClient @EnableHystrix public class HystrixRibbonApplication { public static void main(String[] args) { SpringApplication.run(HystrixRibbonApplication.class, args); } }
c、修改RibbonServiceImpl.class的實現,在getPort方法上面加入@HystrixCommand註解,這樣這個接口就有了熔斷器功能了,其中@HystrixCommand中的fallbackMethod爲執行快速失敗的方法。
package com.cetc.service.impl; import com.cetc.service.IRibbonService; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class RibbonServiceImpl implements IRibbonService { @Autowired private RestTemplate restTemplate; @Override @HystrixCommand(fallbackMethod = "error") public Integer getPort() { return restTemplate.getForObject("http://client/api/test/getPort", Integer.class); } public Integer error() { return 0; } }
d、測試。啓動Eureka-Server、Eureka-Client、Hystrix-Ribbon端口分別爲8670、8673、8677。
正常訪問時:
服務異常時:
2)Feign中使用Hystrix(代碼基於前面的Spring-Cloud之Feign聲明式調用-4進行調整)
a、因爲Feign中自帶了Hystrix功能,所以不需要重新加入依賴。
b、在application.yaml中開啓Hystrix的配置:
feign: hystrix: enabled: true
c、編寫TestHystrix服務錯誤的執行方式,繼承Feign接口
package com.cetc.feign.hystrix; import com.cetc.feign.client.TestFeign; import org.springframework.stereotype.Component; @Component public class TestHystrix implements TestFeign{ @Override public Integer getPort() { return 0; } }
d、在@FeignClient中加入回調的class。
package com.cetc.feign.client; import com.cetc.config.FeignConfiguration; import com.cetc.feign.hystrix.TestHystrix; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; @Component @FeignClient(value = "client", configuration = {FeignConfiguration.class}, fallback = TestHystrix.class) public interface TestFeign { @GetMapping("/api/test/getPort") Integer getPort(); }
e、測試、啓動Eureka-Server、Eureka-Client、Hystrix-Feign端口分別爲8670、8673、8678。
正常訪問:
服務器異常:
六、Hystrix Dashboard監控熔斷器的狀態。
在微服務架構中 ,爲了保證服務實例的可用性,防止服務實例出現故障導致線程阻塞,而出現了熔斷器模型 烙斷器的狀況反映了 個程序的可用性和健壯性,它是一個重要指標。Hystrix Dashboard 是監控 Hystrix 的熔斷器狀況的 個組件,提供了數據監控和 友好的圖形化展示界面。
1)Hystrix Dashboard和Ribbon結合使用(代碼基於上面的熔斷器代碼編寫)
a、加入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</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-netflix-hystrix-dashboard</artifactId> </dependency>
說明:因爲是監控所以加入actuator。hystrix爲起步依賴這裏需要。
b、加入註解@EnableHystrixDashboard
package com.cetc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableEurekaClient @EnableHystrix @EnableHystrixDashboard public class DashboardRibbonApplication { public static void main(String[] args) { SpringApplication.run(DashboardRibbonApplication.class, args); } }
c、加入相關配置到application.yaml,放開actuator的訪問
management: endpoints: web: exposure: include: ["*"]
d、測試。服務包含Eureka-Server、Eureka-Client、Dashboard-Ribbon。端口分別爲8670、8673、8679
測試接口:
訪問:http://127.0.0.1:8679/hystrix
按照提示在輸入框中對應鏈接:http://127.0.0.1:8679/actuator/hystrix.stream,點擊Monitor Stream。測試效果
上面數字代表的意思如下:
2)Hystrix Dashboard和Feign結合使用(代碼基於上面的熔斷器代碼編寫)
a、加入依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</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-netflix-hystrix-dashboard</artifactId> </dependency>
說明:雖然Feign繼承了hystrix,但那不是起步依賴說以這裏還是需要hystrix的依賴
b、加入註解:
package com.cetc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients @EnableHystrix @EnableHystrixDashboard public class DashboardFeignApplication { public static void main(String[] args) { SpringApplication.run(DashboardFeignApplication.class, args); } }
說明:爲什麼還是需要加入@EnableHystrix的註解呢,在使用Dashboard的時候需要這個註解,不然會出現錯誤。
c、修改application.yaml配置
feign: hystrix: enabled: true management: endpoints: web: exposure: include: ["*"]
d、測試。啓動服務有Eureka-Server、Eureka-Client、Dashboard-Feign。端口分別爲8670、8673、8680.
測試正常的接口:
訪問:http://127.0.0.1:8680/hystrix
按提示輸入監控鏈接:http://127.0.0.1:8680/actuator/hystrix.stream,點擊Monitor Stream。效果如下:
數字代表的意義:
七、Turbine聚合監控。
在使用 Hystrix Dashboard 組件監控服務的熔斷器狀況時, 每個服務都有一個HystrixDashboard 主頁,當服務數量很多時,監控非常不方便。爲了同時監控多個服務的熔斷器的狀況, Netflix 開源了 Hystrix 的另 個組件 Turbine Turbine 用於聚合多個 Hystrix Dashboard,將多個 Hystrix Dashboard 組件的數據放在一個頁面上展示,進行集中監控。
1)加入依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-turbine</artifactId> </dependency>
2)修改配置application.yaml
server: port: 8681 eureka: client: service-url: defaultZone: http://127.0.0.1:8670/eureka/ # 實際開發中建議使用域名的方式 spring: application: name: turbine turbine: aggregator: cluster-config: default app-config: dashboard-ribbon,dashboard-feign cluster-name-expression: new String("default") management: endpoints: web: exposure: include: ["*"]
說明:這裏的turbine配置主要是加入服務app-config,兩個服務均是之前寫好的服務。
3)編寫啓動項加入註解:
package com.cetc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; import org.springframework.cloud.netflix.turbine.EnableTurbine; @SpringBootApplication @EnableEurekaClient @EnableHystrixDashboard @EnableTurbine public class TurbineApplication { public static void main(String[] args) { SpringApplication.run(TurbineApplication.class, args); } }
4)測試。啓動服務有Eureka-Server、Eureka-Client、Dashboard-Ribbon、Dashboard-Feign、Turbine。端口分別爲8670、8673、8679、8680、8681.
測試正常服務訪問:
打開:http://127.0.0.1:8681/hystrix
按照提示輸入:http://127.0.0.1:8681/turbine.stream。點擊Monitor Stream。效果如下