簡介
在分佈式系統中服務與服務之間的依賴錯綜複雜,一種不可避免的情況就是某些服務會出現故障,導致依賴於它們的其他服務出現遠程調度的線程阻塞。某個服務的單個點的請求故障會導致用戶的請求處於阻塞狀態,最終的結果是整個服務的線程資源消耗殆盡。由於服務的依賴性,會導致依賴於該故障服務的其他服務也處於線程阻塞狀態,最終導致這些服務的線程資源消耗殆盡,直到不可用,從而導致整個服務系統不可用,即雪崩效應。爲了防止雪崩效應,產生了熔斷器模型。
SpringCloud Netflix實現了斷路器庫的名字叫Hystrix,提供了熔斷器功能,能阻止分佈式系統中出現聯動故障。Hystrix是通過隔離服務的訪問點阻止聯動故障的,並提供了故障解決方案,從而提高了整個分佈式系統的彈性。
當服務的某個API接口的失敗次數在一定時間內小於設定的閾值時,熔斷器處於關閉狀態,該API接口正常提供服務。當該API接口處理請求的失敗次數大於設定的閾值時,Hystrix判定該API接口出現了故障,打開熔斷器,這時請求該API接口會執行快速失敗的邏輯(即fallback回退的邏輯),不執行業務邏輯,請求的線程不會處於阻塞狀態。處於打開狀態的熔斷器,一段時間後會處於半打開狀態,並將一定數量的請求執行正常邏輯,剩餘的請求會執行快速失敗,若執行正常邏輯的請求失敗了,則熔斷器繼續打開,若成功了,則關閉熔斷器。這樣熔斷器就具有了自我修復的能力。
圖中的服務B因爲某些原因失敗,變得不可用,所有對服務B的調用都會超時。當對B的調用失敗達到一個特定的閥值(5秒之內發生20次失敗是Hystrix定義的缺省值), 鏈路就會被處於open狀態,之後所有對服務B的調用都不會被執行, 取而代之的是由斷路器提供的一個表示鏈路open的Fallback消息. Hystrix提供了相應機制,可以讓開發者定義這個Fallbak消息。
open的鏈路阻斷了瀑布式錯誤, 可以讓被淹沒或者錯誤的服務有時間進行修復。這個fallback可以是另外一個Hystrix保護的調用, 靜態數據,或者合法的空值。Fallbacks可以組成鏈式結構,所以最底層調用其它業務服務的第一個Fallback返回靜態數據。
在Ribbon和RestTemplate上使用熔斷器
POM.xml添加依賴
<!--ribbon中使用斷路器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
修改啓動類
加上@EnableHystrix註解,開啓hystrix熔斷器功能
- RibbonApplication.java
package org.springcloud.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
修改Service服務
在hi()方法上加上@HystrixCommand註解。有了該註解hi()方法就啓用了Hystrix熔斷器的功能,其中:
@HystrixCommand 表明該方法爲hystrix包裹,可以對依賴服務進行隔離、降級、快速失敗、快速重試等等hystrix相關功能
- fallbackMethod 降級方法
- commandProperties 普通配置屬性,可以配置HystrixCommand對應屬性,例如採用線程池還是信號量隔離、熔斷器熔斷規則等等
- ignoreExceptions 忽略的異常,默認HystrixBadRequestException不計入失敗
- groupKey() 組名稱,默認使用類名稱
- commandKey 命令名稱,默認使用方法名
fallbackMethod爲處理回退(fallback)邏輯的方法。在本例子,直接返回了一個字符串。在熔斷器打開的狀態下,會執行fallback邏輯。fallback的邏輯最好是返回一些靜態的字符串,不需要處理複雜的邏輯,也不會遠程調用其他服務,這樣方便執行快速失敗,釋放線程資源。如果一定要在fallback邏輯中遠程調用其他服務,最好在遠程調用其他服務時,也加上熔斷器。
- RibbonService.java
package org.springcloud.ribbon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@Service
public class RibbonService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hi(String name){
return restTemplate.getForObject("http://springcloud-eureka-provider/hi?name="+name,String.class);
}
public String hiError(String name){
return "hi,"+name+", use Ribbon + hystrix, eureka-provider is down!";
}
}
依次啓動項目
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-ribbon
全部正常啓動後,停止 springcloud-eureka-provider1 提供者,端口爲:8001服務
訪問命令窗口curl http://eureka-ribbon.com:8100/hi?name=zhaojq,斷路器已經生效,提示:提供者服務掛了
在Feign中使用斷路器
修改application.yml文件
Feign是自帶斷路器的,它沒有默認打開。需要在配置文件中打開它。
- application.yml
spring:
application:
name: springcloud-feign
freemarker:
prefer-file-system-access: false
security:
user:
name: admin
password: 123456
server:
port: 8101
eureka:
instance:
hostname: eureka-feign.com
instance-id: eureka-feign
client:
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer1.com:8897/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer2.com:8898/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer3.com:8899/eureka/
feign:
hystrix:
enabled: true
修改FeignConsumer
在@FeignClient註解的fallback配置加上快速失敗的處理類。該處理類是作爲Feign熔斷器的邏輯處理類,必須實現被@FeignClient修飾的接口。
- FeignConsumer.java
package org.springcloud.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Component
/*指定這個接口所要調用的提供者服務名稱 */
@FeignClient(value = "springcloud-eureka-provider",configuration = FeignConfig.class,fallback = FeignHystrix.class)
public interface FeignConsumer {
@GetMapping(value = "/hi")
String sayHiFromEurekaProvider(@RequestParam(value = "name")String name);
}
新增Feign熔斷器的邏輯處理類
- FeignHystrix.java
package org.springcloud.feign;
import org.springframework.stereotype.Component;
@Component
public class FeignHystrix implements FeignConsumer {
@Override
public String sayHiFromEurekaProvider(String name) {
eturn "hi,"+name+", use Feign + hystrix, eureka-provider is down!";
}
}
依次啓動項目
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-feign
全部正常啓動後,停止 springcloud-eureka-provider1 提供者,端口爲:8001服務
訪問命令窗口curl http://eureka-feign.com:8101/hi,斷路器已經生效,提示:提供者服務掛了
Hystrix Dashboard
Hystrix Dashboard是作爲斷路器狀態的一個組件,提供了數據監控和友好的圖形化界面。
在Ribbon中使用Hystrix Dashboard
POM.xml添加依賴
<!--ribbon中使用斷路器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</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-netflix-hystrix-dashboard</artifactId>
</dependency>
修改application.yml文件
啓動actuator監控
- application.yml
spring:
application:
name: springcloud-ribbon
freemarker:
prefer-file-system-access: false
security:
user:
name: admin
password: 123456
server:
port: 8100
# 自定義配置負載均衡策略
Load_Balance:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
eureka:
instance:
hostname: eureka-ribbon.com
instance-id: eureka-ribbon
client:
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer1.com:8897/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer2.com:8898/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer3.com:8899/eureka/
#actuator端口
management:
endpoints:
web:
#修改訪問路徑 2.0之前默認是/, 2.0默認是 /actuator
base-path: "/actuator"
#開放所有頁面節點 默認只開啓了health、info兩個節點
exposure:
include: '*'
server:
port: 9001
servlet:
context-path: /
ssl:
enabled: false
endpoint:
health:
show-details: always
hystrix:
stream:
enabled: true
修改啓動類
加上@EnableHystrixDashboard註解.
- RibbonApplication.java
package org.springcloud.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableHystrixDashboard
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
依次啓動項目
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-ribbon
在瀏覽器訪問先訪問http://eureka-ribbon.com:8100/hi,然後再訪問http://eureka-ribbon.com:9001/actuator/hystrix.stream,瀏覽器會顯示熔斷器的數據指標
訪問http://eureka-ribbon.com:8100/hystrix
點擊 Moniter Stream
該頁面顯示了熔斷器的谷中數據指標,這些數據指標含義如圖,該圖來自於Hystrix官方文檔,文檔地址:https://github.com/Netflix/Hystrix/wiki
在Feign中使用Hystrix Dashboard
POM.xml添加依賴
Feign自帶的Hystrix依賴不是起步依賴,所以還需要在POM中加上起步依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</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-netflix-hystrix-dashboard</artifactId>
</dependency>
修改application.yml文件
啓動actuator監控
- application.yml
spring:
application:
name: springcloud-feign
freemarker:
prefer-file-system-access: false
security:
user:
name: admin
password: 123456
server:
port: 8101
eureka:
instance:
hostname: eureka-feign.com
instance-id: eureka-feign
client:
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer1.com:8897/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer2.com:8898/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer3.com:8899/eureka/
feign:
hystrix:
enabled: true
management:
endpoints:
web:
base-path: "/actuator"
exposure:
include: "*"
server:
port: 9002
servlet:
context-path: /
ssl:
enabled: false
endpoint:
health:
show-details: always
hystrix:
stream:
enabled: true
修改啓動類
加上@EnableHystrix和@EnableHystrixDashboard註解.
- FeignApplication.java
package org.springcloud.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
@EnableHystrix
@EnableHystrixDashboard
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
依次啓動項目
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-feign
在瀏覽器訪問先訪問http://eureka-feign.com:8101/hi,然後再訪問http://eureka-feign.com:9002/actuator/hystrix.stream,瀏覽器會顯示熔斷器的數據指標
訪問http://eureka-feign.com:8101/hystrix
點擊 Moniter Stream