Spring Cloud Alibaba(三)Sentinel之熔斷降級
- 2019 年 10 月 31 日
- 筆記
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服務
- 訪問地址: http://localhost:9102/hello-feign/yuntian
返回
我是服務提供者,見到你很高興==>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
表示執行了我們預定的回調,服務成功降級了。