較低級別的服務中的服務故障可能導致級聯故障一直到用戶。 當對特定服務的調用超過circuitBreaker.requestVolumeThreshold(默認值:20個請求)且失敗百分比大於circuit.rolllingStats.timeInMilliseconds定義的滾動窗口中的circuitBreaker.errorThresholdPercentage(默認值:> 50%)時(默認值:10秒)
設計原則:
- 防止單個服務的故障,耗盡整個系統服務的容器(比如tomcat)的線程資源,避免分布式環境里大量級聯失敗。通過第三方客戶端訪問(通常是通過網絡)依賴服務出現失敗、拒絕、超時或短路時執行回退邏輯
- 用快速失敗代替排隊(每個依賴服務維護一個小的線程池或信號量,當線程池滿或信號量滿,會立即拒絕服務而不會排隊等待)和優雅的服務降級;當依賴服務失效后又恢復正常,快速恢復
- 提供接近實時的監控和警報,從而能夠快速發現故障和修復。監控信息包括請求成功,失敗(客戶端拋出的異常),超時和線程拒絕。如果訪問依賴服務的錯誤百分比超過閾值,斷路器會跳閘,此時服務會在一段時間內停止對特定服務的所有請求
- 將所有請求外部系統(或請求依賴服務)封裝到HystrixCommand或HystrixObservableCommand對象中,然后這些請求在一個獨立的線程中執行。使用隔離技術來限制任何一個依賴的失敗對系統的影響。每個依賴服務維護一個小的線程池(或信號量),當線程池滿或信號量滿,會立即拒絕服務而不會排隊等待
功能特性:
- 請求熔斷: 當Hystrix Command請求后端服務失敗數量超過一定比例(默認50%), 斷路器會切換到開路狀態(Open). 這時所有請求會直接失敗而不會發送到后端服務. 斷路器保持在開路狀態一段時間后(默認5秒), 自動切換到半開路狀態(HALF-OPEN)。這時會判斷下一次請求的返回情況, 如果請求成功, 斷路器切回閉路狀態(CLOSED), 否則重新切換到開路狀態(OPEN). Hystrix的斷路器就像我們家庭電路中的保險絲, 一旦后端服務不可用, 斷路器會直接切斷請求鏈, 避免發送大量無效請求影響系統吞吐量, 並且斷路器有自我檢測並恢復的能力.
- 服務降級:Fallback相當於是降級操作. 對於查詢操作, 可以實現一個fallback方法, 當請求后端服務出現異常的時候, 可以使用fallback方法返回的值. fallback方法的返回值一般是設置的默認值或者來自緩存
- 依賴隔離(采用艙壁模式,Docker就是艙壁模式的一種):在Hystrix中, 主要通過線程池來實現資源隔離. 通常在使用的時候我們會根據調用的遠程服務划分出多個線程池
- 請求緩存
- 請求合並
Ribbon集成斷路器
1、基於之前的服務,引入Hystrix依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
2、開啟斷路器功能
@EnableCircuitBreaker:加載斷路器配置
@EnableCircuitBreaker
也可以使用@SpringCloudApplication注解:三合一
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
3、創建fallback方法,指定為某個接口的降級
@SpringCloudApplication
public class ConsumerRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerRibbonApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@RestController
@RequestMapping("/api/v1/consumer")
class ProviderController {
private static final String SERVICE_NAME = "provider-server";
private static final String GET_PORT = "/api/v1/provider/port";
@Resource
private RestTemplate restTemplate;
@GetMapping
@HystrixCommand(fallbackMethod = "consumerFallback")
public String consumer() {
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://" + SERVICE_NAME + GET_PORT, String.class, (Object) null);
return forEntity.getBody();
}
public String consumerFallback() {
return "provider error";
}
}
}
hystrix:配置
hystrix:
command:
default:
execution:
isolation:
strategy: SEMAPHORE
thread:
timeoutInMilliseconds: 60000
shareSecurityContext: true
驗證:
訪問消費者:http://localhost:3000/api/v1/consumer
獲得響應:2000
Feign集成斷路器
引入依賴和開啟配置和Ribbon一樣
1、在@FeignClient上聲明
@FeignClient(name = "provider-server", fallback = ProviderClientFallback.class)
@RequestMapping("/api/v1/provider")
public interface ProviderClient {
@GetMapping("/port")
String port();
}
2、開啟配置feign.hystrix.enabled=true
server:
port: 3001
spring:
application:
name: consumer-server-feign
profiles:
active: dev
cloud:
config:
label: master
profile: ${spring.profiles.active}
discovery:
service-id: config-server
enabled: true
feign:
hystrix:
enabled: true
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
3、編寫fallback類
public class ProviderClientFallback implements ProviderClient {
@Override
public String port() {
return "provider error";
}
}
4、在聲明類@FeignClient上指定fallback屬性
@FeignClient(name = "provider-server", fallback = ProviderClientFallback.class)
@RequestMapping("/api/v1/provider")
public interface ProviderClient {
@GetMapping("/port")
String port();
}
驗證:
訪問消費者:http://localhost:3000/api/v1/consumer
獲得響應:2000
關閉生產者服務:http://localhost:3000/api/v1/consumer
獲得響應:provider error
5、換成指定FallbackFactory,可以獲取到異常對象
@FeignClient(name = "provider-server",
fallbackFactory = HystrixClient.HystrixClientFallback.class,
path = "/api/v1/provider")
public interface HystrixClient {
@GetMapping("/port")
String port();
@Component
class HystrixClientFallback implements FallbackFactory<HystrixClient> {
@Override
public HystrixClient create(Throwable throwable) {
return new HystrixClient() {
@Override
public String port() {
return "provider error: " + throwable;
}
};
}
}
}
驗證:
訪問消費者:http://localhost:3000/api/v1/consumer
獲得響應:2000
關閉生產者服務:http://localhost:3000/api/v1/consumer
獲得響應:provider error: java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: provider-server
Hystrix Metrics Stream
包含依賴關系spring-boot-starter-actuator
,設置 management.endpoints.web.exposure.include: hystrix.stream
。這樣做會將/actuator/hystrix.stream
管理端點公開
依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置:
# 全部開放監控端點
management:
endpoints:
web:
exposure:
include: "*"
驗證:
GET /actuator/metrics
GET /actuator/metrics/{requiredMetricName}
{[/actuator/metrics/{requiredMetricName}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
{[/actuator/metrics],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
斷路器:Hystrix儀表板
1、添加依賴項:spring-cloud-starter-netflix-hystrix-dashboard
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
2、使用@EnableHystrixDashboard注解開啟儀表盤
@EnableFeignClients
@SpringCloudApplication
@EnableHystrixDashboard
public class ConsumerFeignApplication {
}
3、訪問/hystrix
並將儀表板指向/hystrix.stream
Hystrix客戶端應用程序中的單個實例的端點。