1. 概述
本文我們來學習 Spring Cloud Alibaba 提供的 Spring Cloud Alibaba Sentinel 元件,對 Spring Cloud 進行整合,實作服務容錯相關的功能。
FROM https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
随着微服務的流行,服務和服務之間的穩定性變得越來越重要。 Sentinel 以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個次元保護服務的穩定性。
Sentinel 具有以下特征:
- 豐富的應用場景: Sentinel 承接了阿裡巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峰填谷、實時熔斷下遊不可用應用等。
- 完備的實時監控: Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級資料,甚至 500 台以下規模的叢集的彙總運作情況。
- 廣泛的開源生态: Sentinel 提供開箱即用的與其它開源架構/庫的整合子產品,例如與 Spring Cloud、Dubbo、gRPC 的整合。您隻需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel。
- 完善的 SPI 擴充點: Sentinel 提供簡單易用、完善的 SPI 擴充點。您可以通過實作擴充點,快速的定制邏輯。例如定制規則管理、适配資料源等。
在開始本文之前,胖友需要對 Sentinel 進行簡單的學習。可以閱讀《Sentinel 極簡入門》文章,将第一二小節看完,在本機搭建一個 Sentinel 控制台。
友情提示:艿艿本機搭建的 Sentinel 控制台啟動在 7070 端口。
2. 流量控制
示例代碼對應倉庫: labx-04-sca-sentinel-demo01-provider
。
在本小節,我們來學習下 Sentinel 的流量控制功能,對應《Sentinel 官方文檔 —— 流量控制》文章。
FROM 《Sentinel 官方文檔 —— 首頁》
流量控制,在網絡傳輸中是一個常用的概念,它用于調整網絡包的發送資料。然而,從系統穩定性角度考慮,在處理請求的速度上,也有非常多的講究。任意時間到來的請求往往是随機不可控的,而系統的處理能力是有限的。我們需要根據系統的處理能力對流量進行控制。Sentinel 作為一個調配器,可以根據需要把随機的請求調整成合适的形狀,如下圖所示:
設計理念
流量控制有以下幾個角度:
Sentinel 的設計理念是讓您自由選擇控制的角度,并進行靈活組合,進而達到想要的效果。
- 資源的調用關系,例如資源的調用鍊路,資源和資源之間的關系;
- 運作名額,例如 QPS、線程池、系統負載等;
- 控制的效果,例如直接限流、冷啟動、排隊等。
下面,我們來搭建一個 Sentinel 流量控制的使用示例。最終示例項目如下圖所示:
2.1 引入依賴
在
pom.xml
檔案中,引入 Spring Cloud Alibaba Sentinel 相關依賴。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-04</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-04-sca-sentinel-demo01-provider</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 檔案,進行依賴版本的管理,防止不相容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 開發團隊推薦了三者的依賴關系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相關依賴,并實作對其的自動配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Sentinel 相關依賴,使用 Sentinel 提供服務保障,并實作對其的自動配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>
通過引入
spring-cloud-starter-alibaba-sentinel
依賴,引入并實作 Sentinel 的自動配置。在該依賴中,已經幫我們自動引入 Sentinel 的大量依賴,非常友善,如下圖所示:
2.2 配置檔案
建立
application.yaml
配置檔案,添加 Sentinel 配置項。配置如下:
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置項,對應 SentinelProperties 配置屬性類
sentinel:
enabled: true # 是否開啟。預設為 true 開啟
eager: true # 是否饑餓加載。預設為 false 關閉
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台位址
filter:
url-patterns: /** # 攔截請求的位址。預設為 /*
Sentinel 配置項,以
spring.cloud.sentinel
開頭,對應 SentinelProperties 配置屬性類。
①
enabled
配置項,設定是否開啟 Sentinel,預設為
true
開啟,是以一般不用主動設定。如果胖友關閉 Sentinel 的功能,例如說在本地開發的時候,可以設定為
false
關閉。
②
eager
配置項,設定是否饑餓加載,預設為
false
關閉。預設情況下,Sentinel 是延遲初始化,在首次使用到 Sentinel 才進行初始化。通過設定為
true
時,在項目啟動時就會将 Sentinel 直接初始化,完成向 Sentinel 控制台進行注冊。
③
transport.dashboard
配置項,設定 Sentinel 控制台位址。
④
filter.url-patterns
配置項,設定攔截請求的位址,預設為
/*
。
在 Sentinel 的子項目
sentinel-spring-webmvc-adapter
中,對 SpringMVC 進行适配,通過 SentinelWebInterceptor 攔截器,實作對 SpringMVC 的請求的攔截,使用 Sentinel 進行保護。通過
filter.url-patterns
配置項,可以定義該攔截器的攔截請求位址。
不過要注意,因為
filter.url-patterns
配置項的預設值為
/*
,隻能攔截根目錄的請求,顯然不滿足我們的日常需求,是以艿艿修改成了
/**
攔截所有請求。不了解的胖友,可以閱讀下《SpringMVC Ant 路徑比對》文章。
2.3 BlockException 處理器
先來對 BlockException 異常做個簡單的了解,在被 Sentinel block 的時候,就會抛出它。BlockException 是一個異常抽象基類,其有 5 個實作類,剛好對應 Sentinel 的 5 種流量控制手段,如下圖所示:
旁白君:暫時找不到 block 适合翻譯成什麼單詞,相對最貼切的可能是阻塞...
在 SentinelWebInterceptor 攔截器中,當請求滿足配置的 Sentinel block 的條件時,Sentinel 會抛出 BlockException 異常。通過定義 BlockExceptionHandler 接口的實作類,可以實作對 BlockException 的異常處理。
預設情況下,BlockExceptionHandler 有一個預設的 DefaultBlockExceptionHandler 實作類,傳回 Block 字元串提示。代碼如下:
public class DefaultBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
// ... 省略其它代碼
PrintWriter out = response.getWriter();
out.print("Blocked by Sentinel (flow limiting)");
}
}
顯然,在我們使用 SpringMVC 提供 Restful API 時,直接傳回字元串提示是不合适的,因為一般是傳回 JSON 字元串,例如說:
{
"code": 1024,
"msg": "Blocked by Sentinel (flow limiting)"
}
是以,我們自定義的 CustomBlockExceptionHandler 實作類,直接抛出 BlockException 異常,最終交給自定義的 SpringMVC 全局異常處理器 ,将 BlockException 異常處理成 JSON 字元串提示傳回。代碼如下:
// CustomBlockExceptionHandler.java
@Component
public class CustomBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
throw e;
}
}
// GlobalExceptionHandler.java
@Component
@ControllerAdvice(basePackages = "cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider") // 隻處理該包下的 Controller 定義的接口
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = BlockException.class) // 因為這裡是示例,是以暫時使用 JSONObject,實際項目最終定義一個 CommonResult。
public JSONObject blockExceptionHandler(BlockException blockException) {
return new JSONObject().fluentPut("code", 1024)
.fluentPut("msg", "請求被攔截,攔截類型為 " + blockException.getClass().getSimpleName());
}
}
友情提示:如果胖友對 SpringMVC 的全局異常處理器不了解的話,可以看看《芋道 Spring Boot SpringMVC 入門》文章的「5. 全局異常處理」小節。
2.4 DemoController
建立 DemoController 類,提供稍後測試流量控制的示例 API。代碼如下:
@RestController
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/echo")
public String echo() {
return "echo";
}
@GetMapping("/test")
public String test() {
return "test";
}
}
2.5 DemoProviderApplication
建立 DemoProviderApplication 類,作為應用啟動類。代碼如下:
@SpringBootApplication
public class DemoProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DemoProviderApplication.class, args);
}
}
2.6 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。在 IDEA 控制台中,可以看到 Sentinel 相關的日志如下:
// ... 省略其它日志
// Sentinel 初始化。有點不合群的日志格式~
INFO: log output type is: file
INFO: log charset is: utf-8
INFO: log base dir is: /Users/yunai/logs/csp/
INFO: log name use pid is: false
// 注冊 SentinelWebInterceptor 攔截器,攔截路徑為 /** 的請求
2020-02-13 23:30:05.574 INFO 49873 --- [ main] c.a.c.s.SentinelWebAutoConfiguration : [Sentinel Starter] register SentinelWebInterceptor with urlPatterns: [/**]
② 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。此時,我們可以看到
demo-provider
應用。如下圖所示:
③ 使用浏覽器,通路下 http://127.0.0.1:8080/demo/echo 接口 10 次。然後點選 Sentinel 控制台的「實時監控」菜單,可以看到該接口的請求情況。如下圖所示:
④ 點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到
/demo/echo
資源。如下圖所示:
⑤ 點選
/demo/echo
資源所在列的「流控」按鈕,彈出「新增流控規則」。填寫流控規則,如下圖所示:
- 這裡,我們建立的是比較簡單的規則,僅允許
資源被每秒調用一次。/demo/echo
- 更多詳細的配置項的說明,胖友後續一定要認真看《Sentinel 官方文檔 —— 流量控制》文章,這是 Sentinel 提供的多種規則中最最最常用的一種。
⑥ 點選「新增」按鈕,完成流控規則的添加。此時,會自動跳轉到「流控規則」菜單。如下圖所示:
⑦ 使用浏覽器,通路 http://127.0.0.1:8080/demo/echo 接口兩次,會有一次被 Sentinel 流量控制而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 FlowException",
"code": 1024
}
- 流量控制對應 FlowException 異常,是以這裡會看到哈。
此時,點選 Sentinel 控制台的「實時監控」菜單,可以看到該接口被拒絕的統計。如下圖所示:
3. 熔斷降級
示例代碼對應倉庫: labx-04-sca-sentinel-demo01-provider
。
在本小節,我們來學習下 Sentinel 的流量控制功能,對應《Sentinel 官方文檔 —— 熔斷降級》文章。
FROM 《Sentinel 官方文檔 —— 首頁》
除了流量控制以外,降低調用鍊路中的不穩定資源也是 Sentinel 的使命之一。由于調用關系的複雜性,如果調用鍊路中的某個資源出現了不穩定,最終會導緻請求發生堆積。
設計理念
Sentinel 和 Hystrix 的原則是一緻的: 當檢測到調用鍊路中某個資源出現不穩定的表現,例如請求響應時間長或異常比例升高的時候,則對這個資源的調用進行限制,讓請求快速失敗,避免影響到其它的資源而導緻級聯故障。
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一樣的方法。
Hystrix 通過 線程池隔離 的方式,來對依賴(在 Sentinel 的概念中對應 資源)進行了隔離。這樣做的好處是資源和資源之間做到了最徹底的隔離。缺點是除了增加了線程切換的成本(過多的線程池導緻線程數目過多),還需要預先給各個資源做線程池大小的配置設定。
Sentinel 對這個問題采取了兩種手段:
1、通過并發線程數進行限制
和資源池隔離的方法不同,Sentinel 通過限制資源并發線程的數量,來減少不穩定資源對其它資源的影響。這樣不但沒有線程切換的損耗,也不需要您預先配置設定線程池的大小。當某個資源出現不穩定的情況下,例如響應時間變長,對資源的直接影響就是會造成線程數的逐漸堆積。當線程數在特定資源上堆積到一定的數量之後,對該資源的新請求就會被拒絕。堆積的線程完成任務後才開始繼續接收請求。
2、通過響應時間對資源進行降級
除了對并發線程數進行控制以外,Sentinel 還可以通過響應時間來快速降級不穩定的資源。當依賴的資源出現響應時間過長後,所有對該資源的通路都會被直接拒絕,直到過了指定的時間視窗之後才重新恢複。
下面,我們來搭建一個 Sentinel 熔斷降級制的使用示例。本着省時省力(努力偷懶)的原則,我們直接複用「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目。
3.1 DemoController
在 DemoController 類中,額外添加
demo/sleep
接口,通過 sleep 100 毫秒,模拟延遲較高的接口。代碼如下:
@GetMapping("/sleep")
public String sleep() throws InterruptedException {
Thread.sleep(100L);
return "sleep";
}
3.2 簡單測試
友情提示:在測試的過程中,咱會發現之前配置的流量控制規則不見了,不要慌,後面會詳細述說。
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:8080/demo/sleep 接口,保證
/demo/sleep
資源的初始化。
③ 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到
/demo/sleep
資源。
之後,點選
/demo/sleep
資源所在列的「降級」按鈕,彈出「新增降級規則」。填寫降級規則,如下圖所示:Sentinel 控制台 - 新增降級規則
- 這裡,我們建立的是比較簡單的規則,當
資源在 5 秒的時間視窗中,如果平均響應時間超過 1 ms,則進行熔斷降級。/demo/sleep
Sentinel 一共有 3 種方式來衡量資源是否穩定:
FROM 《Sentinel 官方文檔 —— 流量控制》
1、平均響應時間 (
DEGRADE_GRADE_RT
)
當 1s 内持續進入 5 個請求,對應時刻的平均響應時間(秒級)均超過門檻值(
,以 ms 為機關),那麼在接下的時間視窗(
count
中的
DegradeRule
,以 s 為機關)之内,對這個方法的調用都會自動地熔斷(抛出
timeWindow
DegradeException
)。
注意 Sentinel 預設統計的 RT 上限是 4900 ms,超出此門檻值的都會算作 4900 ms,若需要變更此上限可以通過啟動配置項
-Dcsp.sentinel.statistic.max.rt=xxx
來配置。
2、異常比例 (
DEGRADE_GRADE_EXCEPTION_RATIO
)
當資源的每秒請求量 >= 5,并且每秒異常總數占通過量的比值超過門檻值(
中的
DegradeRule
)之後,資源進入降級狀态,即在接下的時間視窗(
count
中的
DegradeRule
,以 s 為機關)之内,對這個方法的調用都會自動地傳回。異常比率的門檻值範圍是
timeWindow
[0.0, 1.0]
,代表 0% - 100%。
3、異常數 (
DEGRADE_GRADE_EXCEPTION_COUNT
)
當資源近 1 分鐘的異常數目超過門檻值之後會進行熔斷。注意由于統計時間視窗是分鐘級别的,若
小于 60s,則結束熔斷狀态後仍可能再進入熔斷狀态。
timeWindow
④ 點選「新增」按鈕,完成降級規則的添加。此時,會自動跳轉到「降級規則」菜單。如下圖所示:
⑤ 使用浏覽器,通路 http://127.0.0.1:8080/demo/sleep 接口 6 次,就會有被 Sentinel 服務降級而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 DegradeException",
"code": 1024
}
- 熱點參數限流對應 DegradeException 異常,是以這裡會看到哈。
此時,點選 Sentinel 控制台的「實時監控」菜單,可以看到該接口被拒絕的統計。如下圖所示:
耐心等待幾秒,過了這個時間視窗後,繼續通路 http://127.0.0.1:8080/demo/sleep 接口,又可以成功傳回了。
4. 熱點參數限流
示例代碼對應倉庫: labx-04-sca-sentinel-demo01-provider
。
在本小節,我們來學習下 Sentinel 的熱點參數限流功能,對應《Sentinel 官方文檔 —— 熱點參數限流》文章。
FROM 《Sentinel 官方文檔 —— 熱點參數限流》
何為熱點?熱點即經常通路的資料。很多時候我們希望統計某個熱點資料中通路頻次最高的 Top K 資料,并對其通路進行限制。比如:
熱點參數限流,會統計傳入參數中的熱點參數,并根據配置的限流門檻值與模式,對包含熱點參數的資源調用進行限流。熱點參數限流可以看做是一種特殊的流量控制,僅對包含熱點參數的資源調用生效。 Sentinel 利用 LRU 政策統計最近最常通路的熱點參數,結合令牌桶算法來進行參數級别的流控。熱點參數限流支援叢集模式。
- 商品 ID 為參數,統計一段時間内最常購買的商品 ID 并進行限制。
- 使用者 ID 為參數,針對一段時間内頻繁通路的使用者 ID 進行限制。
下面,我們來搭建一個 Sentinel 熱點參數限流的使用示例。本着省時省力(努力偷懶)的原則,我們直接複用「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目。
4.1 DemoController
在 DemoController 類中,額外添加
demo/product_info
接口,用于熱點參數限流的示例 API。代碼如下:
@GetMapping("/product_info")
@SentinelResource("demo_product_info_hot")
public String productInfo(Integer id) {
return "商品編号:" + id;
}
- 在方法上,我們添加了
注解,自定義了@SentinelResource
資源。demo_product_info_hot
為什麼不直接使用
sentinel-spring-webmvc-adapter
庫,自動給該
demo/product_info
接口生成的
/demo/product_info
資源呢?
- 原因:因為
庫提供的 SentinelWebInterceptor 攔截器在調用 Sentinel 用戶端時,并未傳入參數,是以無法進行熱點參數限流sentinel-spring-webmvc-adapter
- 解決:使用 Sentinel 提供的
注解,自定義了@SentinelResource
資源。然後,通過 Spring AOP 攔截該方法的調用,實作 Sentinel 的處理邏輯。在本小節中,就是為了熱點參數限流demo_product_info_hot
友情提示,關于 @SentinelResource
注解,我們在「TODO. 注解支援」小節中,會專門講解下。
4.2 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:8080/demo/product_info?id=1 接口,保證
/demo/product_info
資源的初始化。
③ 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到
demo_product_info_hot
資源。
之後,點選
demo_product_info_hot
資源所在列的「熱點」按鈕,彈出「新增熱點規則」。填寫熱點規則,如下圖所示:
- 這裡,我們隻設定了參數索引為 0,統計視窗時長為 60 秒,請求最大次數為 10。更多設定,我們繼續往下看。
④ 點選「新增」按鈕,完成熱點規則的添加。此時,會自動跳轉到「熱點規則」菜單。如下圖所示:
之後,點選
demo_product_info_hot
資源所在列的「編輯」按鈕,彈出「編輯熱點規則」。填寫熱點規則,如下圖所示:
- 這裡,我們配置了當第一個參數的值為 1 時,限制在統計視窗中,請求最大次數為 1。
點選「 儲存」按鈕,完成編輯。
⑤ 使用浏覽器,通路 http://127.0.0.1:8080/demo/product_info?id=1 接口 2 次,就會有被 Sentinel 熱點參數限流而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 ParamFlowException",
"code": 1024
}
- 熔斷降級對應 ParamFlowException 異常,是以這裡會看到哈。
此時,點選 Sentinel 控制台的「實時監控」菜單,可以看到該接口被拒絕的統計。如下圖所示:
此時,我們通路 http://127.0.0.1:8080/demo/product_info?id=2 接口,不會存在限流的情況。而是在快速通路 10 次,才會被限流。
😈 有一點要特别注意,熱點參數限流看起來和「2. 流量控制」基于 QPS 的限流是比較相似的。不過很大的差異是,熱點參數限流是針對每個參數,分别計數來限流。舉個例子,在目前示例的熱點規則下:
- 針對每個
對應的 http://127.0.0.1:8080/demo/product_info?id=${id} 接口,在每 60 秒内,分别允許通路 10 次。id
- 針對
的情況,作為特殊(例外)配置,在每 60 秒内,僅僅允許通路 1 次。id = 1
詳細的,胖友自己可以簡單測試下,感受會非常明顯哈。
5. 系統自适應限流
示例代碼對應倉庫: labx-04-sca-sentinel-demo01-provider
。
在本小節,我們來學習下 Sentinel 的系統自适應限流功能,對應《Sentinel 官方文檔 —— 系統自适應限流》文章。
FROM 《Sentinel 官方文檔 —— 首頁》
Sentinel 同時提供系統次元的自适應保護能力。防止雪崩,是系統防護中重要的一環。當系統負載較高的時候,如果還持續讓請求進入,可能會導緻系統崩潰,無法響應。在叢集環境下,網絡負載均衡會把本應這台機器承載的流量轉發到其它的機器上去。如果這個時候其它的機器也處在一個邊緣狀态的時候,這個增加的流量就會導緻這台機器也崩潰,最後導緻整個叢集不可用。
針對這個情況,Sentinel 提供了對應的保護機制,讓系統的入口流量和系統的負載達到一個平衡,保證系統在能力範圍之内處理最多的請求。
下面,我們來搭建一個 Sentinel 系統自适應限流的使用示例。本着省時省力(努力偷懶)的原則,我們直接複用「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目。
5.1 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「系統規則」菜單,然後點選右上角「新增系統規則」按鈕,彈出「新增系統保護規則」。填寫降級規則,如下圖所示:
- 這裡,為了測試友善,我們建立了一條 CPU 超過 1% 後,自動進行系統限流。
Sentinel 一共有 5 種系統規則:
FROM 《Sentinel 官方文檔 —— 系統自适應限流》
1、Load 自适應(僅對 Linux/Unix-like 機器生效)
系統的 load1 作為啟發名額,進行自适應系統保護。當系統 load1 超過設定的啟發值,且系統目前的并發線程數超過估算的系統容量時才會觸發系統保護(BBR 階段)。系統容量由系統的
估算得出。設定參考值一般是
maxQps * minRt
CPU cores * 2.5
。
2、CPU usage(1.5.0+ 版本)
當系統 CPU 使用率超過門檻值即觸發系統保護(取值範圍 0.0-1.0),比較靈敏。
3、平均 RT
當單台機器上所有入口流量的平均 RT 達到門檻值即觸發系統保護,機關是毫秒。
4、并發線程數
當單台機器上所有入口流量的并發線程數達到門檻值即觸發系統保護。
5、入口 QPS
當單台機器上所有入口流量的 QPS 達到門檻值即觸發系統保護。
③ 使用浏覽器,通路 http://127.0.0.1:8080/demo/echo 接口,直接就被 Sentinel 系統自适應限流而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 SystemBlockException",
"code": 1024
}
此時,點選 Sentinel 控制台的「實時監控」菜單,可以看到該接口被拒絕的統計。如下圖所示:
6. 黑白名單控制
示例代碼對應倉庫: labx-04-sca-sentinel-demo01-provider
。
在本小節,我們來學習下 Sentinel 的黑白名單控制功能,對應《Sentinel 官方文檔 —— 黑白名單控制》文章。
FROM 《Sentinel 官方文檔 —— 黑白名單控制》
很多時候,我們需要根據調用來源來判斷該次請求是否允許放行,這時候可以使用 Sentinel 的來源通路控制(黑白名單控制)的功能。來源通路控制根據資源的請求來源(origin)限制資源是否通過:
- 若配置白名單則隻有請求來源位于白名單内時才可通過;
- 若配置黑名單則請求來源位于黑名單時不通過,其餘的請求通過。
下面,我們來搭建一個 Sentinel 黑白名單控制的使用示例。本着省時省力(努力偷懶)的原則,我們直接複用「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目。
6.1 RequestOriginParser
在 Sentinel 的子項目
sentinel-spring-webmvc-adapter
中,定義了 RequestOriginParser 接口,從請求中解析到調用來源,例如說使用 IP、請求頭
user
、請求頭
appName
。
因為我們要使用 Sentinel 黑白名單控制的功能,是以需要獲得請求的調用來。RequestOriginParser 暫時沒有提供預設的實作,是以我們自定義 CustomRequestOriginParser 實作類,解析請求頭
s-user
作為調用來源。代碼如下:
@Component
public class CustomRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// <X> 從 Header 中,獲得請求來源
String origin = request.getHeader("s-user");
// <Y> 如果為空,給一個預設的
if (StringUtils.isEmpty(origin)) {
origin = "default";
}
return origin;
}
}
- 在
處,我們從請求頭的<X>
對應的值,作為請求來源。注意,Sentinel 黑白名單的控制,一般是服務和服務之間的調用。例如說,配置訂單服務允許調用使用者服務。"s-user"
- 在
處,我們判斷未獲得請求來源的時候,設定預設為<Y>
。原因是,Sentinel 提供的 AuthorityRuleChecker 在進行黑白名單控制時,如果請求來源為空,直接就通過了 =。=default
6.2 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:8080/demo/echo 接口,保證
/demo/echo
資源的初始化。
③ 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到
/demo/echo
資源。
之後,點選
/demo/echo
資源所在列的「授權」按鈕,彈出「新增授權規則」。填寫授權規則,如下圖所示:
- 這裡,我們配置
資源,僅僅允許來源為/demo/echo
的請求才可以通路。test
③ 點選「新增」按鈕,完成授權規則的添加。此時,會自動跳轉到「授權規則」菜單。如下圖所示:
④ 使用浏覽器,通路 http://127.0.0.1:8080/demo/echo 接口時,就會有被 Sentinel 黑白名單控制而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 AuthorityException",
"code": 1024
}
- 熱點參數限流對應 AuthorityException 異常,是以這裡會看到哈。
此時,點選 Sentinel 控制台的「實時監控」菜單,可以看到該接口被拒絕的統計。如下圖所示:
我們來使用 Postman 來模拟一個來源為
test
的請求,如下圖所示:
7. Sentinel 用戶端 API
示例代碼對應倉庫: labx-04-sca-sentinel-demo01-provider
。
為了減少開發的複雜程度,Sentinel 對大部分的主流架構做了适配,例如 SpringMVC、WebFlux、Dubbo、Spring Cloud、RocketMQ 等等。我們隻需要引入對應的
sentinel-apache-xxx-adapter
依賴,即可友善地整合 Sentinel。
- 在上述的示例中,我們使用的就是 Sentinel 提供的
對 SpringMVC 的示例。sentinel-spring-webmvc-adapter
- 更多 Sentinel 的适配架構介紹,可見《Sentinel 官方文檔 —— 主流架構的适配》文章。
不過,Sentinel 并不能适配所有架構,此時我們可以使用 Sentinel 用戶端 API,手動進行資源的保護。在《Sentinel 官方文檔 —— 如何使用》文章的定義資源和其它 API 兩個小節,詳細的介紹了如何使用 Sentinel 用戶端 API。
下面,我們來搭建一個 Sentinel 用戶端 API 的使用示例。本着省時省力(努力偷懶)的原則,我們直接複用「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目。
7.1 DemoController
在 DemoController 類中,額外添加
demo/entry_demo
接口,在内部使用 Sentinel 用戶端 API 來進行資源的保護。代碼如下:
@GetMapping("/entry_demo")
public String entryDemo() {
Entry entry = null;
try {
// <1> 通路資源
entry = SphU.entry("entry_demo");
// <2> ... 執行業務邏輯
return "執行成功";
} catch (BlockException ex) { // <3>
return "被拒絕";
} finally {
// <4> 釋放資源
if (entry != null) {
entry.exit();
}
}
}
- 整個邏輯,和我們使用 Java 進行 I/O 操作的代碼比較像,通過
經典套路。try catch finally
-
處,調用 Sentinel 的<1>
方法,通路資源。其中,參數SphU#entry(String name)
就是在 Sentinel 中定義的資源名。如果通路資源被拒絕,例如說被限流或降級,則會抛出 BlockException 異常。name
-
處,編寫具體的業務邏輯代碼。<2>
-
處,處理通路資源被拒絕所抛出的 BlockException 異常。這裡,我們是直接傳回<3>
的字元串。"被拒絕"
-
處,調用 Sentinel 的<4>
方法,釋放對資源的通路。注意,entry 和 exit 必須成對出現,不然資源一直被持有者。Entry#exit()
這裡我們編寫的示例是比較簡單的,推薦胖友後續自己看下
sentinel-spring-webmvc-adapter
提供的 AbstractSentinelInterceptor 攔截器對 Sentinel 用戶端 API 的使用。
7.2 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:8080/demo/entry_demo 接口,保證
entry_demo
資源的初始化。
③ 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到
entry_demo
資源。如下圖所示:
之後,我們給
entry_demo
資源添加一個每秒僅允許調用一次的流控規則。如下圖所示:
④ 使用浏覽器,通路 http://127.0.0.1:8080/demo/echo 接口兩次,會有一次被 Sentinel 流量控制而拒絕,最終傳回如下 JSON 字元串:
|
8. 注解支援
示例代碼對應倉庫: labx-04-sca-sentinel-demo01-provider
。
在「7. Sentinel 用戶端 API」小節中,我們使用 Sentinel 用戶端 API,手動進行資源的保護。但是我們會發現,對代碼的入侵太強,需要将業務邏輯進行修改。是以,Sentinel 提供了
@SentinelResource
注解聲明自定義資源,通過 Spring AOP 攔截該注解的方法,自動調用 Sentinel 用戶端 API,進行指定資源的保護。
實際上,在「4. 熱點參數限流」小節裡,已經使用了
@SentinelResource
注解。下面,我們來看看《Sentinel 官方文檔 —— 注解支援》對它的介紹:
注意:注解方式埋點不支援 private 方法。
@SentinelResource
用于定義資源,并提供可選的異常處理和 fallback 配置項。
@SentinelResource
注解包含以下屬性:
-
:資源名稱,必需項(不能為空)value
-
:entry 類型,可選項(預設為entryType
)EntryType.OUT
-
/blockHandler
:blockHandlerClass
對應處理blockHandler
的函數名稱,可選項。blockHandler 函數通路範圍需要是BlockException
,傳回類型需要與原方法相比對,參數類型需要和原方法相比對并且最後加一個額外的參數,類型為public
。blockHandler 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定BlockException
為對應的類的blockHandlerClass
對象,注意對應的函數必需為 static 函數,否則無法解析。Class
-
:fallback 函數名稱,可選項,用于在抛出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有類型的異常(除了fallback
-
:裡面排除掉的異常類型)進行處理。fallback 函數簽名和位置要求:exceptionsToIgnore
- 傳回值類型必須與原函數傳回值類型一緻;
- 方法參數清單需要和原函數一緻,或者可以額外多一個
類型的參數用于接收對應的異常。Throwable
- fallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定
為對應的類的fallbackClass
對象,注意對應的函數必需為 static 函數,否則無法解析。Class
-
:預設的 fallback 函數名稱,可選項,通常用于通用的 fallback 邏輯(即可以用于很多服務或方法)。預設 fallback 函數可以針對所有類型的異常(除了defaultFallback
裡面排除掉的異常類型)進行處理。若同時配置了 fallback 和 defaultFallback,則隻有 fallback 會生效。defaultFallback 函數簽名要求:exceptionsToIgnore
- 傳回值類型必須與原函數傳回值類型一緻;
- 方法參數清單需要為空,或者可以額外多一個
類型的參數用于接收對應的異常。Throwable
- defaultFallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定
為對應的類的fallbackClass
對象,注意對應的函數必需為 static 函數,否則無法解析。Class
-
:用于指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣抛出。exceptionsToIgnore
特别地,若 blockHandler 和 fallback 都進行了配置,則被限流降級而抛出
BlockException
時隻會進入
blockHandler
處理邏輯。若未配置
blockHandler
、
fallback
和
defaultFallback
,則被限流降級時會将
BlockException
直接抛出(若方法本身未定義 throws BlockException 則會被 JVM 包裝一層
UndeclaredThrowableException
)。
下面,我們來搭建一個 Sentinel
@SentinelResource
注解的示例。本着省時省力(努力偷懶)的原則,我們繼續複用「2. 流量控制」小節的 lab-46-sentinel-demo 項目。
8.1 DemoController
在 DemoController 類中,額外添加
demo/annotations_demo
接口,使用
@SentinelResource
注解來聲明資源的保護。代碼如下:
@GetMapping("/annotations_demo")
@SentinelResource(value = "annotations_demo_resource",
blockHandler = "blockHandler",
fallback = "fallback")
public String annotationsDemo(@RequestParam(required = false) Integer id) throws InterruptedException {
if (id == null) {
throw new IllegalArgumentException("id 參數不允許為空");
}
return "success...";
}
// BlockHandler 處理函數,參數最後多一個 BlockException,其餘與原函數一緻.
public String blockHandler(Integer id, BlockException ex) {
return "block:" + ex.getClass().getSimpleName();
}
// Fallback 處理函數,函數簽名與原函數一緻或加一個 Throwable 類型的參數.
public String fallback(Integer id, Throwable throwable) {
return "fallback:" + throwable.getMessage();
}
① 在方法中,如果未傳
id
參數時,抛出 IllegalArgumentException 異常。
② 在方法上,添加
@SentinelResource
注解,聲明資源的保護。可能比較懵逼的是,如果有
blockHandler
和
fallback
屬性都配置的情況下,怎麼配置設定異常呢?實際上,Sentinel 文檔中已經提到這個情況的解答
特别地,若和
blockHandler
都進行了配置,則被限流降級而抛出 BlockException 時隻會進入 blockHandler 處理邏輯。
fallback
-
和fallback
的差異點,在于blockHandler
隻能處理 BlockException 異常,blockHandler
能夠處理所有異常。fallback
- 如果都配置的情況下,BlockException 異常配置設定給
處理,其它異常配置設定給blockHandler
處理。fallback
8.2 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:8080/demo/annotations_demo 接口,保證
annotations_demo_resource
資源的初始化。
③ 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到
annotations_demo_resource
資源。如下圖所示:
之後,我們給
annotations_demo_resource
資源添加一個每 60 秒的異常比例是 10% 的降級規則。如下圖所示:
③ 使用浏覽器,通路 http://127.0.0.1:8080/demo/annotations_demo 接口,響應結果為
"fallback:id 參數不允許為空"
。原因是,因為傳入的
id
為空,是以抛出 IllegalArgumentException 異常,最終交給
#fallback(...)
方法處理。
繼續不停通路 http://127.0.0.1:8080/demo/annotations_demo 接口,達到在 ② 中配置的降級規則的閥值,會響應結果為
block:DegradeException
。原因是,達到降級的閥值後,抛出的是 DegradeException 異常,而該異常是 BlockingException 的子類,是以交給
#blockHandler(...)
方法處理。
9. 規則管理及推送
友情提示:本小節内容會略微難一丢丢,請保持你耐心閱讀完。然後,在跟着後續小節的示例,會更加容易了解。
在《Sentinel 官方文檔 —— 在生産環境中使用 Sentinel》的「規則管理及推送」小節,詳細的介紹了 Sentinel 規則的管理與推送方式的三種模式。核心内容如下:
FROM 《Sentinel 官方文檔 —— 在生産環境中使用 Sentinel》
推送模式 | 說明 | 優點 | 缺點 |
---|---|---|---|
原始模式 | API 将規則推送至用戶端并直接更新到記憶體中,擴充寫資料源( ) | 簡單,無任何依賴 | 不保證一緻性;規則儲存在記憶體中,重新開機即消失。嚴重不建議用于生産環境 |
Pull 模式 | 擴充寫資料源( ), 用戶端主動向某個規則管理中心定期輪詢拉取規則,這個規則中心可以是 RDBMS、檔案 等 | 簡單,無任何依賴;規則持久化 | 不保證一緻性;實時性不保證,拉取過于頻繁也可能會有性能問題。 |
Push 模式 | 擴充讀資料源( ),規則中心統一推送,用戶端通過注冊監聽器的方式時刻監聽變化,比如使用 Nacos、Zookeeper 等配置中心。這種方式有更好的實時性和一緻性保證。生産環境下一般采用 push 模式的資料源。 | 規則持久化;一緻性;快速 | 引入第三方依賴 |
- 詳細的每個模式的說明,一定要認真認真認證看下文檔,這對了解接下來的内容,非常重要喲。
9.1 原始模式
可能胖友會和艿艿一開始有相同的了解誤區。Sentinel 控制台并不持久化規則,而是通過
sentinel-transport-simple-http
依賴提供的 HTTP API,将我們在 Sentinel 控制台編輯的規則,推送給內建 Sentinel 用戶端的應用的記憶體中。如下圖所示:
- 因為我們引入了
依賴,是以應用在啟動的時候,會注冊到 Sentinel 控制台。是以,我們在 Sentinel 控制台的「機器清單」菜單,可以看到每個應用的示例。如下圖所示:sentinel-transport-simple-http
- 同時,
依賴提供了 HTTP API 接口,提供給 Sentinel 進行規則的推送,監控的查詢。具體有哪些接口,我們來一起看下,如下圖所示:sentinel-transport-simple-http
這樣一個梳理,是不是對原始模式的了解,稍微會清晰一些些了。另外,我們可以參考《Sentinel 官方文檔 —— 如何使用》的「規則的種類」小節,直接使用代碼配置規則,通過調用
FlowRuleManager#loadRules(List<FlowRule> rules)
方法,将 Sentinel 規則加載到記憶體當中。
9.2 Pull 和 Push 模式
對于 Pull 模式和 Push 模式,都是由 Sentinel 用戶端從不同的資料源,加載配置規則。并不是所有的資料源自身支援實時推送功能,因而導緻 Sentinel 的規則推送模式分成非實時的 Pull 模式,和實時的 Push 模式。
在《Sentinel 官方文檔 —— 動态規則》中,将 Pull 和 Push 模式,統稱為動态規則。同時,也提供了每種資料源的使用示例。😈 當然在下文中,我們會搭建在 Spring Boot 項目中的使用示例。
另外,考慮到更友善的配置 Sentinel 規則,需要将 Sentinel 控制台和配置中心等資料源進行內建。具體的,需要我們參考官方如下文檔,進行自己實作。
FROM 《Sentinel 官方文檔 —— 在生産環境中使用 Sentinel》
從 Sentinel 1.4.0 開始,Sentinel 控制台提供
和
DynamicRulePublisher
接口用于實作應用次元的規則推送和拉取,并提供了相關的示例。Sentinel 提供應用次元規則推送的示例頁面(
DynamicRuleProvider
/v2/flow
),使用者改造控制台對接配置中心後可直接通過 v2 頁面推送規則至配置中心。改造詳情可參考 應用次元規則推送示例。
部署多個控制台執行個體時,通常需要将規則存至 DB 中,規則變更後同步向配置中心推送規則。
10. 使用 Nacos 作為資料源
示例代碼對應倉庫: labx-04-sca-sentinel-nacos-provider
。
本小節,我們使用 Nacos 作為 Sentinel 規則的資料源,并使用 Push 模式推送規則。對于 Nacos 不了解的胖友,可以先看看《Nacos 極簡入門》文章。
下面,我們從「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目,複制出
labx-04-sca-sentinel-nacos-provider
項目,改造成接入 Nacos 作為資料源。
10.1 引入依賴
在
pom.xml
檔案中,額外引入相關依賴。
<!-- Sentinel 對 Nacos 作為資料源的支援 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
引入
sentinel-datasource-nacos
依賴,實作 Sentinel 對 Nacos 作為資料源的支援。
10.2 配置檔案
修改
application.yaml
配置檔案,添加 Sentinel 使用 Nacos 作為資料源。完整配置如下:
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置項,對應 SentinelProperties 配置屬性類
sentinel:
enabled: true # 是否開啟。預設為 true 開啟
eager: true # 是否饑餓加載。預設為 false 關閉
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台位址
filter:
url-patterns: /** # 攔截請求的位址。預設為 /*
# Sentinel 規則的資料源,是一個 Map 類型。key 為資料源名,可自定義;value 為資料源的具體配置
datasource:
ds1:
# 對應 DataSourcePropertiesConfiguration 類
nacos:
server-addr: 127.0.0.1:8848 # Nacos 伺服器位址
namespace: # Nacos 命名空間
group-id: DEFAULT_GROUP # Nacos 分組
data-id: ${spring.application.name}-flow-rule # Nacos 配置集編号
data-type: json # 資料格式
rule-type: FLOW # 規則類型
通過添加
spring.cloud.sentinel.datasource
配置項,設定接入的 Sentinel 規則的資料源。注意它是一個 Map 類型,其中:
① key:為資料源名,可自定義,無特殊含義。這裡我們添加了一個
ds1
,如果胖友想要更多資料源,可以繼續添加噢。
② value:為資料源的具體配置,對應 DataSourcePropertiesConfiguration 類,可以選擇
file
、
nacos
、
zk
、
apollo
、
redis
任一作為資料的資料源。這裡我們選擇
nacos
來接入 Nacos 作為資料源。
-
:資料源對應的 Sentinel 規則類型,在 RuleType 類枚舉。這裡我們設定了rule-type
對應流量控制的規則。FLOW
-
:資料源的資料格式,預設為data-type
。這裡我們設定了json
,是以稍後建立的 Nacos 配置集的資料格式要為json
。JSON
-
:Nacos 伺服器位址。server-addr
-
:Nacos 分組。namespace
-
:Nacos 配置集編号。推薦配置集編号的命名規則為data-id
,是以這裡我們設定為${applicationName}-${ruleType}
,即demo-provider-flow-rule
應用的流控規則。demo-provider
10.3 建立 Nacos 配置集
理論來說,我們需要改造 Sentinel 控制台的代碼,将 Sentinel 接入 Nacos 作為規則的資料源。但是考慮到涉及的内容較多,本文暫時跳過,感興趣的胖友,可以閱讀應用次元規則推送示例文章。
咳咳咳,理論來說,Sentinel 控制台應該内置了對 Nacos 資料源的接入。
也是以,我門直接在 Nacos 中,建立一個配置集
demo-provider-flow-rule
,具體内容如下圖:
在配置内容中,我們設定了一個針對
/demo/echo
資源,每秒允許通路 5 次。每個字段的說明如下:
[
{
"resource": "/demo/echo",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- 注意是數組哈~
FROM 《Sentinel 控制規則 —— 流量控制》
-
:資源名,即限流規則的作用對象resource
-
: 限流門檻值count
-
: 限流門檻值類型(QPS 或并發線程數)grade
-
: 流控針對的調用來源,若為limitApp
則不區分調用來源default
-
: 調用關系限流政策strategy
-
: 流量控制效果(直接拒絕、Warm Up、勻速排隊)controlBehavior
10.4 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
點選 Sentinel 控制台的「流控規則」菜單,可以看到應用中已經有一條流控規則,是從 Nacos 資料源加載而來的。如下圖所示:
③ 使用浏覽器,快速通路 http://127.0.0.1:8080/demo/echo 接口 6 次,最後 1 次會被 Sentinel 流量控制而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 FlowException",
"code": 1024
}
11. 使用 Apollo 作為資料源
示例代碼對應倉庫: labx-04-sca-sentinel-apollo-provider
。
本小節,我們使用 Apollo 作為 Sentinel 規則的資料源,并使用 Push 模式推送規則。對于 Nacos 不了解的胖友,可以先看看《Apollo 極簡入門》文章。
下面,我們從「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目,複制出
labx-04-sca-sentinel-apollo-provider
項目,改造成接入 Apollo 作為資料源。
11.1 引入依賴
在
pom.xml
檔案中,額外引入相關依賴。
<!-- Sentinel 對 Apollo 作為資料源的支援 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-apollo</artifactId>
</dependency>
引入
sentinel-datasource-apollo
依賴,實作 Sentinel 對 Apollo 作為資料源的支援。
11.2 配置檔案
修改
application.yaml
配置檔案,添加 Sentinel 使用 Apollo 作為資料源。完整配置如下:
server:
port: 18080 # 伺服器端口,設定為 18080 避免和本地的 Apollo 端口沖突
# Apollo 相關配置項
app:
id: ${spring.application.name} # 使用的 Apollo 的項目(應用)編号
apollo:
meta: http://127.0.0.1:8080 # Apollo Meta Server 位址
bootstrap:
enabled: true # 是否開啟 Apollo 配置預加載功能。預設為 false。
eagerLoad:
enable: true # 是否開啟 Apollo 支援日志級别的加載時機。預設為 false。
namespaces: application # 使用的 Apollo 的命名空間,預設為 application。
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置項,對應 SentinelProperties 配置屬性類
sentinel:
enabled: true # 是否開啟。預設為 true 開啟
eager: true # 是否饑餓加載。預設為 false 關閉
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台位址
filter:
url-patterns: /** # 攔截請求的位址。預設為 /*
# Sentinel 規則的資料源,是一個 Map 類型。key 為資料源名,可自定義;value 為資料源的具體配置
datasource:
ds1:
# 對應 DataSourcePropertiesConfiguration 類
apollo:
namespaceName: application # Apollo 命名空間
flowRulesKey: sentinel.flow-rule # Apollo 配置 key
data-type: json # 資料格式
rule-type: FLOW # 規則類型
📚 純 Apollo 相關配置
在
app
和
apollo
配置項,是 Apollo 相關的配置。這裡我們使用 Apollo 應用為
demo-provider
。其它的配置項,胖友看注釋即可,更詳細的可以閱讀《芋道 Spring Boot 配置中心 Apollo 入門》文章。
📚 Sentinel 資料源相關配置
通過添加
spring.cloud.sentinel.datasource
配置項,設定接入的 Sentinel 規則的資料源。注意它是一個 Map 類型,其中:
① key:為資料源名,可自定義,無特殊含義。這裡我們添加了一個
ds1
,如果胖友想要更多資料源,可以繼續添加噢。
② value:為資料源的具體配置,對應 DataSourcePropertiesConfiguration 類,可以選擇
file
、
nacos
、
zk
、
apollo
、
redis
任一作為資料的資料源。這裡我們選擇
apollo
來接入 Apollo 作為資料源。
-
:資料源對應的 Sentinel 規則類型,在 RuleType 類枚舉。這裡我們設定了rule-type
對應流量控制的規則。FLOW
-
:資料源的資料格式,預設為data-type
。這裡我們設定了json
,是以稍後建立的 Nacos 配置集的資料格式要為json
。JSON
-
:Apollo 命名空間。namespaceName
-
:Apollo 配置 Key。推薦配置項的 Key 的命名規則為flowRulesKey
,是以這裡我們設定為sentinel.${ruleType}
,即目前應用的流控規則。sentinel.flow-rule
11.4 建立 Apollo 配置
理論來說,我們需要改造 Sentinel 控制台的代碼,将 Sentinel 接入 Apollo 作為規則的資料源。但是考慮到涉及的内容較多,本文暫時跳過,感興趣的胖友,可以閱讀應用次元規則推送示例文章。
咳咳咳,理論來說,Sentinel 控制台應該内置了對 Apollo 資料源的接入。
也是以,我門直接在 Apollo 中,建立一個配置項
sentinel.flow-rule
,具體内容如下圖:
在配置項的 Value 中,我們設定了一個針對
/demo/echo
資源,每秒允許通路 5 次。每個字段的說明如下:
[
{
"resource": "/demo/echo",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- 注意是數組哈~
FROM 《Sentinel 控制規則 —— 流量控制》
-
:資源名,即限流規則的作用對象resource
-
: 限流門檻值count
-
: 限流門檻值類型(QPS 或并發線程數)grade
-
: 流控針對的調用來源,若為limitApp
則不區分調用來源default
-
: 調用關系限流政策strategy
-
: 流量控制效果(直接拒絕、Warm Up、勻速排隊)controlBehavior
11.5 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
點選 Sentinel 控制台的「流控規則」菜單,可以看到應用中已經有一條流控規則,是從 Apollo 資料源加載而來的。如下圖所示:
③ 使用浏覽器,快速通路 http://127.0.0.1:18080/demo/echo 接口 6 次,最後 1 次會被 Sentinel 流量控制而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 FlowException",
"code": 1024
}
12. 使用 File 作為資料源
示例代碼對應倉庫:lab-46-sentinel-demo-file。
本小節,我們使用 File(檔案) 作為 Sentinel 規則的資料源。注意,生産環境下,不建議使用 File 作為資料源。
下面,我們從「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目,複制出
labx-04-sca-sentinel-apollo-provider
項目,改造成接入 File 作為資料源。
12.1 配置檔案
修改
application.yaml
配置檔案,添加 Sentinel 使用 File 作為資料源。完整配置如下:
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置項,對應 SentinelProperties 配置屬性類
sentinel:
enabled: true # 是否開啟。預設為 true 開啟
eager: true # 是否饑餓加載。預設為 false 關閉
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台位址
filter:
url-patterns: /** # 攔截請求的位址。預設為 /*
# Sentinel 規則的資料源,是一個 Map 類型。key 為資料源名,可自定義;value 為資料源的具體配置
datasource:
ds1:
# 對應 DataSourcePropertiesConfiguration 類
file:
file: /Users/yunai/Sentinel/demo-provider/flow-rule.json # 配置規則所在檔案。
recommendRefreshMs: 3000 # 定時讀取實作重新整理,預設為 3000 毫秒。
data-type: json # 資料格式
rule-type: FLOW # 規則類型
通過添加
spring.cloud.sentinel.datasource
配置項,設定接入的 Sentinel 規則的資料源。注意它是一個 Map 類型,其中:
① key:為資料源名,可自定義,無特殊含義。這裡我們添加了一個
ds1
,如果胖友想要更多資料源,可以繼續添加噢。
② value:為資料源的具體配置,對應 DataSourcePropertiesConfiguration 類,可以選擇
file
、
nacos
、
zk
、
apollo
、
redis
任一作為資料的資料源。這裡我們選擇
file
來接入 Nacos 作為資料源。
-
:資料源對應的 Sentinel 規則類型,在 RuleType 類枚舉。這裡我們設定了rule-type
對應流量控制的規則。FLOW
-
:資料源的資料格式,預設為data-type
。這裡我們設定了json
,是以稍後建立的 Nacos 配置集的資料格式要為json
。JSON
-
:Nacos 伺服器位址。server-addr
-
:配置規則所在檔案。file
-
:定時讀取實作重新整理,預設為 3000 毫秒。recommendRefreshMs
12.2 建立 File 檔案
建立
/Users/yunai/Sentinel/demo-provider/flow-rule.json
檔案,存放應用
demo-provider
的 Sentinel 流量控制的規則。其内容如下:
[
{
"resource": "/demo/echo",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- 注意是數組哈~
FROM 《Sentinel 控制規則 —— 流量控制》
-
:資源名,即限流規則的作用對象resource
-
: 限流門檻值count
-
: 限流門檻值類型(QPS 或并發線程數)grade
-
: 流控針對的調用來源,若為limitApp
則不區分調用來源default
-
: 調用關系限流政策strategy
-
: 流量控制效果(直接拒絕、Warm Up、勻速排隊)controlBehavior
12.3 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
點選 Sentinel 控制台的「流控規則」菜單,可以看到應用中已經有一條流控規則,是從 File 資料源加載而來的。如下圖所示:
③ 使用浏覽器,快速通路 http://127.0.0.1:8080/demo/echo 接口 6 次,最後 1 次會被 Sentinel 流量控制而拒絕,最終傳回如下 JSON 字元串:
{
"msg": "請求被攔截,攔截類型為 FlowException",
"code": 1024
}
旁白君:File 資料源還支援 Pull 模式推送規則的持久化,不過實際基本不會使用到。如果感興趣的胖友,可以閱讀《芋道 Spring Boot 服務容錯 Sentinel 入門》文章的「12. 使用 File 作為資料源」小節。
13. 叢集流控
艿艿暫時沒有去研究 Sentinel 的叢集流控功能,主要看 Token Server 暫時未提供高可用方案,這個上到生産肯定是有蠻大風險的。感興趣的胖友,可以先閱讀如下文章:
- 《Sentinel 官方文檔 —— 叢集流控》
- 《Sentinel 實戰 - 叢集流控》
- 《Sentinel 實戰 - 叢集流控環境搭建》
14. 整合 Feign
示例代碼對應倉庫:
- 服務提供者:
labx-04-sca-sentinel-demo01-provider
- 服務消費者:
labx-04-sca-sentinel-feign-consumer
本小節我們來進行 Feign 和 Sentinel 的整合,該功能由 Spring Cloud Alibaba Sentinel 的
feign
子產品提供。
Feign 是一款聲明式 HTTP 用戶端,可以更快捷、更優雅的實作 HTTP API 調用。不了解的胖友,推薦閱讀下《芋道 Spring Cloud 聲明式調用 Feign 入門》文章。
下面,我們新搭建一個服務消費者項目
labx-04-sca-sentinel-feign-consumer
,并将「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目作為服務提供者,使用 Feign 進行 HTTP API 調用。最終示例項目如下圖所示:
14.1 引入依賴
建立服務消費者項目
labx-04-sca-sentinel-feign-consumer
,在
pom.xml
檔案中,主要引入 Sentinel 和 Feign 相關依賴。代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-04</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-04-sca-sentinel-feign-consumer</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 檔案,進行依賴版本的管理,防止不相容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 開發團隊推薦了三者的依賴關系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相關依賴,并實作對其的自動配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Sentinel 相關依賴,使用 Sentinel 提供服務保障,并實作對其的自動配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 引入 Spring Cloud OpenFeign 相關依賴,使用 OpenFeign 提供聲明式調用,并實作對其的自動配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
每個依賴的作用,胖友可以看艿艿在其上添加的注釋。
14.2 配置檔案
建立
application.yaml
配置類,添加相應配置項。配置如下:
spring:
application:
name: demo-consumer
cloud:
# Sentinel 配置項,對應 SentinelProperties 配置屬性類
sentinel:
enabled: true # 是否開啟。預設為 true 開啟
eager: true # 是否饑餓加載。預設為 false 關閉
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台位址
filter:
url-patterns: /** # 攔截請求的位址。預設為 /*
server:
port: 8081
feign:
sentinel:
enabled: true # 開啟 Sentinel 對 Feign 的支援,預設為 false 關閉。
重點是
feign.sentinel.enabled
配置項,設定為
true
,開啟 Sentinel 對 Feign 的支援。
14.3 DemoProviderFeignClient
建立 DemoProviderFeignClient 接口,實作對服務
demo-provider
聲明式調用。代碼如下:
@FeignClient(name = "demo-provider", url = "http://127.0.0.1:8080",
fallbackFactory = DemoProviderFeignClientFallbackFactory.class)
public interface DemoProviderFeignClient {
@GetMapping("/demo/echo")
String echo();
}
通過
@FeignClient
注解,聲明一個 FeignClient 用戶端。
①
name
屬性,設定 FeignClient 用戶端的名字。
②
url
屬性,設定調用服務的位址。因為我們沒有引入注冊中心,是以我們直接設定稍後啟動的服務
demo-provider
的位址。
③
fallbackFactory
屬性,設定 fallback 工廠類。fallback 的作用是,用于在 HTTP 調動失敗而抛出異常的時候,提供 fallback 處理邏輯。
友情提示:Feign 和 Sentinel 進行整合的時候,fallback 并不是必須條件,主要看是否想要提供 fallback 處理邏輯。
14.3.1 DemoProviderFeignClientFallbackFactory
建立 DemoProviderFeignClientFallbackFactory 類,用于建立 DemoProviderFeignClientFallback 的工廠類。代碼如下:
@Component
public class DemoProviderFeignClientFallbackFactory implements FallbackFactory<DemoProviderFeignClientFallback> {
@Override
public DemoProviderFeignClientFallback create(Throwable throwable) {
// 可以給 DemoProviderFeignClientFallback 提供具體的 throwable 異常
return new DemoProviderFeignClientFallback(throwable);
}
}
注意,類上需要添加
@Component
注解,因為
@FeignClient
注解的
fallbackFactory
屬性,是通過從 Spring 中擷取
fallbackFactory
對應類型的 Bean。
14.3.2 DemoProviderFeignClientFallback
建立 DemoProviderFeignClientFallback 類,提供 DemoProviderFeignClient 的 fallback 處理邏輯。代碼如下:
public class DemoProviderFeignClientFallback implements DemoProviderFeignClient {
private Throwable throwable;
public DemoProviderFeignClientFallback(Throwable throwable) {
this.throwable = throwable;
}
@Override
public String echo() {
return "fallback:" + throwable.getClass().getSimpleName();
}
}
注意,類上需要添加
@Component
注解,因為
@FeignClient
注解的
fallbackFactory
屬性,是通過從 Spring 中擷取
fallbackFactory
對應類型的 Bean。
14.3.2 DemoProviderFeignClientFallback
建立 DemoProviderFeignClientFallback 類,提供 DemoProviderFeignClient 的 fallback 處理邏輯。代碼如下:
public class DemoProviderFeignClientFallback implements DemoProviderFeignClient {
private Throwable throwable;
public DemoProviderFeignClientFallback(Throwable throwable) {
this.throwable = throwable;
}
@Override
public String echo() {
return "fallback:" + throwable.getClass().getSimpleName();
}
}
注意,要實作 DemoProviderFeignClient 接口,這樣每個實作方法,能夠一一對應,進行 fallback 處理邏輯。
14.4 ConsumerController
建立 ConsumerController 類,提供一個通過 Feign 調用服務提供者的 HTTP 接口。代碼如下:
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private DemoProviderFeignClient demoProviderFeignClient;
@GetMapping("/echo")
public String echo() {
return demoProviderFeignClient.echo();
}
}
14.5 DemoConsumerApplication
建立 DemoConsumerApplication 類,建立應用啟動類。代碼如下:
@SpringBootApplication
@EnableFeignClients
public class DemoConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoConsumerApplication.class, args);
}
}
@EnableFeignClients
注解,添加在類上,聲明開啟 Feign 用戶端的功能。
14.6 簡單測試
① 通過「2. 流量控制」小節的 DemoProviderApplication 啟動服務提供者。使用 DemoConsumerApplication 啟動服務消費者。
② 通路服務消費者的 http://127.0.0.1:8081/consumer/echo 接口,保證相關資源的初始化。
③ 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到看到 Feign 的服務提供者産生的
GET:http://127.0.0.1:8080/demo/echo
資源。如下圖所示:
點選
GET:http://127.0.0.1:8080/demo/echo
資源所在列的「流控」按鈕,彈出「新增流控規則」。填寫流控規則,如下圖所示:
- 這裡,我們建立的是比較簡單的規則,僅允許該資源被每秒調用一次。
④ 使用浏覽器,通路 http://127.0.0.1:8081/consumer/echo 接口兩次,會有一次被 Sentinel 流量控制而拒絕,傳回結果為
fallback:FlowException
。這說明 Feign 和 Sentinel 的整合成功,并進入 DemoProviderFeignClient 的 fallback 處理邏輯。
15. 整合 RestTemplate
本小節我們來進行 Feign 和 RestTemplate 的整合,該功能由 Spring Cloud Alibaba Sentinel 的
custom
子產品提供。
RestTemplate 是 Spring 提供的用于通路 Rest 服務的 HTTP 用戶端,提供了多種可以便捷調用遠端 HTTP 服務的方法,能夠大大提高用戶端的開發效率。
下面,我們新搭建一個服務消費者項目
labx-04-sca-sentinel-resttemplate-consumer
,并将「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目作為服務提供者,使用 Feign 進行 HTTP API 調用。最終示例項目如下圖所示:項目結構
15.1 引入依賴
示例代碼對應倉庫:
- 服務提供者:
labx-04-sca-sentinel-demo01-provider
- 服務消費者:
labx-04-sca-sentinel-resttemplate-consumer
建立服務消費者項目
labx-04-sca-sentinel-resttemplate-consumer
,在
pom.xml
檔案中,主要引入 Sentinel 相關依賴。代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-04</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-04-sca-sentinel-resttemplate-consumer</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 檔案,進行依賴版本的管理,防止不相容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 開發團隊推薦了三者的依賴關系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相關依賴,并實作對其的自動配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Sentinel 相關依賴,使用 Sentinel 提供服務保障,并實作對其的自動配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>
每個依賴的作用,胖友可以看艿艿在其上添加的注釋。
15.2 配置檔案
建立
application.yaml
配置類,添加相應配置項。配置如下:
spring:
application:
name: demo-consumer
cloud:
# Sentinel 配置項,對應 SentinelProperties 配置屬性類
sentinel:
enabled: true # 是否開啟。預設為 true 開啟
eager: true # 是否饑餓加載。預設為 false 關閉
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台位址
filter:
url-patterns: /** # 攔截請求的位址。預設為 /*
server:
port: 8081
resttemplate:
sentinel:
enabled: true # 開啟 Sentinel 對 Feign 的支援,預設為 true 開啟。
重點是
resttemplate.sentinel.enabled
配置項,設定為
true
,開啟 Sentinel 對 RestTemplate 的支援。不過因為預設就為
true
,是以可以不配置。
15.3 RestTemplateConfiguration
建立 RestTemplateConfiguration 配置類,建立 RestTemplate Bean。代碼如下:
@Configuration
public class RestTemplateConfiguration {
@Bean
@SentinelRestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
重點! 通過
@SentinelRestTemplate
注解,聲明 Sentinel 對 RestTemplate 的支援。
另外,
@SentinelRestTemplate
注解提供了
blockHandler
、
blockHandlerClass
、
fallback
、
fallbackClass
屬性,作用和
@SentinelResource
注解是一緻的。
15.4 ConsumerController
建立 ConsumerController 類,提供一個通過 RestTemplate 調用服務提供者的 HTTP 接口。代碼如下:
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/echo")
public String echo() {
return restTemplate.getForObject("http://127.0.0.1:8080/demo/echo", String.class);
}
}
15.5 DemoConsumerApplication
建立 DemoConsumerApplication 類,建立應用啟動類。代碼如下:
@SpringBootApplication
public class DemoConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoConsumerApplication.class, args);
}
}
15.6 簡單測試
① 通過「2. 流量控制」小節的 DemoProviderApplication 啟動服務提供者。使用 DemoConsumerApplication 啟動服務消費者。
② 通路服務消費者的 http://127.0.0.1:8081/consumer/echo 接口,保證相關資源的初始化。
③ 使用浏覽器,通路下 http://127.0.0.1:7070/ 位址,進入 Sentinel 控制台。
然後,點選 Sentinel 控制台的「簇點鍊路」菜單,可以看到看到 Feign 的服務提供者産生的
GET:http://127.0.0.1:8080/demo/echo
資源。如下圖所示:
點選
GET:http://127.0.0.1:8080/demo/echo
資源所在列的「流控」按鈕,彈出「新增流控規則」。填寫流控規則,如下圖所示:
- 這裡,我們建立的是比較簡單的規則,僅允許該資源被每秒調用一次。
④ 使用浏覽器,通路 http://127.0.0.1:8081/consumer/echo 接口兩次,會有一次被 Sentinel 流量控制而拒絕,傳回結果為
RestTemplate request block by sentinel
。這說明 RestTemplate 和 Sentinel 的整合成功,并傳回 Sentinel 對 RestTemplate 預設的 block 的響應。
16. 監控端點
示例代碼對應倉庫: labx-04-sca-sentinel-actuator-provider
。
Spring Cloud Alibaba Sentinel 的
endpoint
子產品,基于 Spring Boot Actuator,提供了自定義監控端點
sentinel
,擷取 Sentinel 的配置項,和各種規則。
同時, Sentinel 拓展了 Spring Boot Actuator 内置的
health
端點,通過自定義的 SentinelHealthIndicator,擷取和 Sentinel 控制台和資料源的連接配接狀态。
友情提示:對 Spring Boot Actuator 不了解的胖友,可以後續閱讀《芋道 Spring Boot 監控端點 Actuator 入門》文章。
下面,我們從「2. 流量控制」小節的
labx-04-sca-sentinel-demo01-provider
項目,複制出
labx-04-sca-sentinel-actuator-provider
項目,快速搭建 Sentinel 監控端點的使用示例。
16.1 引入依賴
在
pom.xml
檔案中,額外引入 Spring Boot Actuator 相關依賴。代碼如下:
<!-- 實作對 Actuator 的自動化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
16.2 配置檔案
修改
application.yaml
配置檔案,額外增加 Spring Boot Actuator 配置項。配置如下:
management:
endpoints:
web:
exposure:
include: '*' # 需要開放的端點。預設值隻打開 health 和 info 兩個端點。通過設定 * ,可以開放所有端點。
endpoint:
# Health 端點配置項,對應 HealthProperties 配置類
health:
enabled: true # 是否開啟。預設為 true 開啟。
show-details: ALWAYS # 何時顯示完整的健康資訊。預設為 NEVER 都不展示。可選 WHEN_AUTHORIZED 當經過授權的使用者;可選 ALWAYS 總是展示。
每個配置項的作用,胖友看下艿艿添加的注釋。如果還不了解的話,後續看下《芋道 Spring Boot 監控端點 Actuator 入門》文章。
16.3 簡單測試
① 使用 DemoProviderApplication 啟動示例應用。
② 通路應用的
nacos-discovery
監控端點 http://127.0.0.1:8080/actuator/sentinel,傳回結果如下圖:
③ 通路應用的
health
監控端點 http://127.0.0.1:8080/actuator/health,傳回結果如下圖:
17. 更多的配置項資訊
Spring Cloud Alibaba Sentinel 提供的配置項挺多的,我們參考文檔将配置項一起梳理下。
Spring Cloud Alibaba Sentinel 提供了這些配置選項:
Sentinel 基礎配置
配置項 | 說明 | 預設值 |
---|---|---|
or | Sentinel項目名 | |
| Sentinel自動化配置是否生效 | true |
| 是否提前觸發 Sentinel 初始化 | false |
| WarmUp 模式中的 冷啟動因子 | 3 |
| Sentinel 日志檔案所在的目錄 | |
| Sentinel 日志檔案名是否需要帶上 pid | false |
Sentinel 控制台相關
配置項 | 說明 | 預設值 |
---|---|---|
| 應用與Sentinel控制台互動的端口,應用本地會起一個該端口占用的HttpServer | 8719 |
| Sentinel 控制台位址 | |
| 應用與Sentinel控制台的心跳間隔時間 | |
| 此配置的用戶端IP将被注冊到 Sentinel Server 端 | |
| metric檔案字元集 | UTF-8 |
| Sentinel metric 單個檔案的大小 | |
| Sentinel metric 總檔案數量 |
Servlet 相關
配置項 | 說明 | 預設值 |
---|---|---|
| Servlet Filter的加載順序。Starter内部會構造這個filter | Integer.MIN_VALUE |
| 資料類型是數組。表示Servlet Filter的url pattern集合 | /* |
| Enable to instance CommonFilter | true |
| 自定義的跳轉 URL,當請求被限流時會自動跳轉至設定好的 URL |
網關 Zuul 相關
配置項 | 說明 | 預設值 |
---|---|---|
| SentinelZuulPreFilter 的 order | 10000 |
| SentinelZuulPostFilter 的 order | 1000 |
| SentinelZuulErrorFilter 的 order | -1 |
網關 Spring Cloud Gateway 相關
配置項 | 說明 | 預設值 |
---|---|---|
| Spring Cloud Gateway 流控處理邏輯 (選擇 or ) | |
| Spring Cloud Gateway 響應模式為 'redirect' 模式對應的重定向 URL | |
| Spring Cloud Gateway 響應模式為 'response' 模式對應的響應内容 | |
| Spring Cloud Gateway 響應模式為 'response' 模式對應的響應碼 | 429 |
| Spring Cloud Gateway 響應模式為 'response' 模式對應的 content-type | application/json |
至此,我們已經完成 Spring Cloud Alibaba Sentinel 的學習。如下是 Sentinel 相關的官方文檔:
- 《Sentinel 官方文檔》
- 《Spring Cloud Alibaba 官方文檔 —— Sentinel》
- 《Spring Cloud Alibaba 官方示例 —— Sentinel》