Spring Cloud Alibaba(三)Sentinel之熔斷降級
本專案演示如何使用 Sentinel 完成 Spring Cloud 應用的熔斷降級呼叫。
Sentinel 是阿里巴巴開源的分散式系統的流量防衛元件,Sentinel 把流量作為切入點,從流量控制,熔斷降級,系統負載保護等多個維度保護服務的穩定性。
OpenFeign是一款宣告式、模板化的HTTP客戶端, Feign可以幫助我們更快捷、優雅地呼叫HTTP API,需要了解OpenFeign使用基礎,可以參考cloud-feign示例原始碼。
本專案服務註冊中心使用nacos,服務提供者使用Spring Cloud Alibaba(一) 如何使用nacos服務註冊和發現建立的ali-nacos-provider服務
Sentinel介紹
隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
Sentinel 具有以下特徵:
- 1.豐富的應用場景
Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、訊息削峰填谷、叢集流量控制、實時熔斷下游不可用應用等。
- 2.完備的實時監控
Sentinel 同時提供實時的監控功能。您可以在控制檯中看到接入應用的單臺機器秒級資料,甚至 500 臺以下規模的叢集的彙總執行情況。
- 3.廣泛的開源生態
Sentinel 提供開箱即用的與其它開源框架/庫的整合模組,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
- 4.完善的 SPI 擴充套件點
Sentinel 提供簡單易用、完善的 SPI 擴充套件介面。您可以通過實現擴充套件介面來快速地定製邏輯。例如定製規則管理、適配動態資料來源等。
Sentinel 分為兩個部分
- 核心庫(Java 客戶端)不依賴任何框架/庫,能夠執行於所有 Java 執行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支援。
- 控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接執行,不需要額外的 Tomcat 等應用容器。
Sentinel主要特性
Sentinel開源生態
熔斷降級
對呼叫鏈路中不穩定的資源進行熔斷降級是保障高可用的重要措施之一。由於呼叫關係的複雜性,如果呼叫鏈路中的某個資源不穩定,最終會導致請求發生堆積。Sentinel 熔斷降級會在呼叫鏈路中某個資源出現不穩定狀態時(例如呼叫超時或異常比例升高),對這個資源的呼叫進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯錯誤。當資源被降級後,在接下來的降級時間視窗之內,對該資源的呼叫都自動熔斷(預設行為是丟擲 DegradeException)
降級策略
- 平均響應時間 (DEGRADE_GRADE_RT):當 1s 內持續進入 5 個請求,對應時刻的平均響應時間(秒級)均超過閾值(count,以 ms 為單位),那麼在接下的時間視窗(DegradeRule 中的 timeWindow,以 s 為單位)之內,對這個方法的呼叫都會自動地熔斷(丟擲 DegradeException)。
- 異常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):當資源的每秒請求量 >= 5,並且每秒異常總數佔通過量的比值超過閾值(DegradeRule 中的 count)之後,資源進入降級狀態。
- 異常數 (DEGRADE_GRADE_EXCEPTION_COUNT):當資源近 1 分鐘的異常數目超過閾值之後會進行熔斷。
熔斷降級程式碼實現
服務提供方
建立ali-nacos-provider專案
- 首先, 依賴nacos 註冊中心
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
複製程式碼
- 定義服務提供方介面
@RestController
@Slf4j
public class HelloController {
@GetMapping(value = "/hello/{str}",produces = "application/json")
public String hello(@PathVariable String str) {
log.info("-----------收到消費者請求-----------");
log.info("收到消費者傳遞的引數:" + str);
String result = "我是服務提供者,見到你很高興==>" + str;
log.info("提供者返回結果:" + result);
return result;
}
}
複製程式碼
服務提消費方
建立ali-nacos-sentinel-feign專案
1.首先,pom.xml新增依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</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-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
複製程式碼
2.定義FeignClient,及其降級配置
- 定義FeignClient
package com.easy.ansFeign.service;
import com.easy.ansFeign.fallback.HelloServiceFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "ali-nacos-provider",fallbackFactory = HelloServiceFallbackFactory.class)
public interface HelloService {
/**
* 呼叫服務提供方的輸出介面.
*
* @param str 使用者輸入
* @return hello result
*/
@GetMapping("/hello/{str}")
String hello(@PathVariable("str") String str);
}
複製程式碼
- 定義fallback 工廠,獲取異常
@Component
public class HelloServiceFallbackFactory implements FallbackFactory<HelloServiceFallback> {
@Override
public HelloServiceFallback create(Throwable throwable) {
return new HelloServiceFallback(throwable);
}
}
複製程式碼
- 定義具體的fallback 實現
public class HelloServiceFallback implements HelloService {
private Throwable throwable;
HelloServiceFallback(Throwable throwable) {
this.throwable = throwable;
}
/**
* 呼叫服務提供方的輸出介面.
*
* @param str 使用者輸入
* @return
*/
@Override
public String hello(String str) {
return "服務呼叫失敗,降級處理。異常資訊:" + throwable.getMessage();
}
}
複製程式碼
- 測試入口
@RestController
public class TestController {
@Autowired
private HelloService helloService;
@GetMapping("/hello-feign/{str}")
public String feign(@PathVariable String str) {
return helloService.hello(str);
}
}
複製程式碼
使用示例
示例關聯專案
在Spring Cloud Alibaba(一) 如何使用nacos服務註冊和發現基礎上,我們新建了ali-nacos-sentinel-feign專案,並呼叫ali-nacos-provider專案用作該示例的服務提供方,有以下二個專案做測試。
ali-nacos-provider:服務提供者,服務名:ali-nacos-provider,埠:9000 ali-nacos-sentinel-feign:服務消費者,服務名:ali-nacos-sentinel-feign,埠:9102
執行示例測試
首先要啟動服務註冊中心 nacos、ali-nacos-provider服務及ali-nacos-sentinel-feign服務
返回
我是服務提供者,見到你很高興==>yuntian
複製程式碼
表示我們的服務成功呼叫到了
- 關閉ali-nacos-provider服務,訪問: http://localhost:9102/hello-feign/yuntian
返回
服務呼叫失敗,降級處理。異常資訊:com.netflix.client.ClientException: Load balancer does not have available server for client: ali-nacos-provider
複製程式碼
表示執行了我們預定的回撥,服務成功降級了。