1. 背景
隨著微服務的流行,服務和服務之間的穩(wěn)定性變得越來越重要。以流量為切入點,從流量控制、熔斷降級、系統(tǒng)負載保護等多個維度保護服務的穩(wěn)定性。
1. Sentinel 介紹
Sentinel 提供一個輕量級的開源控制臺,它提供機器發(fā)現(xiàn)以及健康情況管理、監(jiān)控(單機和集群),規(guī)則管理和推送的功能。
1.1 知識
Sentinel 的組成:
- (1) Sentinel 核心庫, 即基本的類庫的使用。
- (2) Dashboard 控制臺,即web頁面的使用。
核心庫介紹
本章節(jié)主要說 核心庫 的使用。
使用 Sentinel 來進行資源保護,主要分為幾個步驟:
- 定義資源
- 定義規(guī)則
- 檢驗規(guī)則是否生效
也就是說:
- 先把可能需要保護的資源定義好(即埋點)
- 之后再配置規(guī)則,規(guī)則描述了什么方式來保護資源。
- 聲明了資源,后續(xù)在任何時候靈活地定義各種流量控制規(guī)則。
資源
資源:可以是指一個服務,一個服務里的方法,或者是一段代碼。寫代碼時,考慮某段代碼是否需要保護,如果需要就將之定義為一個資源。
定義資源的方式
sentinel 支持都多種方式來定義資源,常見的有:
- 方式一:整合到常見的主流框架,比如 Web Servlet、Dubbo、Spring Cloud
- 方式二:拋出異常的方式,使用 SphU 這個類的 try-catch 方式
- 方式三:返回布爾值方式定義資源,使用 SphO 提供 if-else 風格的 API
- 方式四:注解方式定義資源,使用 @SentinelResource 注解 。
- 方式五:異步調用支持,使用 SphU.asyncEntry 異步方法。
示例有:
拋出異常的方式 來定義資源
使用 SphU 這個類的 try-catch 風格的 API。當“資源”發(fā)生了限流之后會拋出 BlockException,然后捕捉異常進行限流之后的邏輯處理。
示例代碼如下:
try (Entry entry = SphU.entry("resourceName")) {
// 被保護的業(yè)務邏輯
// do something here...
} catch (BlockException ex) {
// 資源訪問阻止,被限流或被降級
// 在此處進行相應的處理操作
}
規(guī)則
Sentinel 支持以下幾種規(guī)則:
- 流量控制規(guī)則
- 熔斷降級規(guī)則
- 系統(tǒng)保護規(guī)則
- 來源訪問控制規(guī)則
- 熱點參數(shù)規(guī)則
流量控制規(guī)則(FlowRule)
支持 QPS 模式(1)或并發(fā)線程數(shù)模式(0)。
熔斷降級規(guī)則(DegradeRule)
熔斷策略,支持慢調用比例/異常比例/異常數(shù)策略
系統(tǒng)保護規(guī)則 (SystemRule)
結合應用的 Load、CPU 使用率、總體平均 RT、入口 QPS 和并發(fā)線程數(shù)等幾個維度的監(jiān)控指標,通過自適應的流控策略,讓系統(tǒng)的入口流量和系統(tǒng)的負載達到一個平衡
來源訪問控制規(guī)則 (AuthorityRule)
即黑名單,白名單規(guī)則。
規(guī)則的持久化
建議和 nacos 一起使用,方法見本文后面章節(jié)。
1.2 在service層使用 Sentinel
一般java web 項目都會有 controller 層, service 層,dao層,我們要在 service 層使用的是可以這么做。
(1)添加依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2) 在服務層加注解:
@Service
public class TestService {
@SentinelResource(value = "sayHello")
public String sayHello(String name) {
return "Hello, " + name;
}
}
@SentinelResource 注解用來標識資源是否被限流、降級。上述例子上該注解的屬性 value 指示了一個資源名稱。
@SentinelResource 還提供了其它額外的屬性如 blockHandler,blockHandlerClass,fallback 用于表示限流或降級的操作
一般我們需要實現(xiàn)一個降級后的處理,比如上面的 fallback 指示一個降級后字符串返回值告知觸發(fā)了熔斷降級。
另外,Sentinel 控制臺提供一個輕量級的控制臺,它提供機器發(fā)現(xiàn)、單機資源實時監(jiān)控、集群資源匯總,以及規(guī)則管理的功能。您只需要對應用進行簡單的配置,就可以使用這些功能。我們在后面用一個章節(jié)來介紹它。
1.3 和 Feign 一起使用
Sentinel 適配了組件。
(1) 先引入 spring-cloud-starter-alibaba-sentinel
的依賴
(2) 再引入feign依賴
引入 spring-cloud-starter-openfeign
依賴**,使 Sentinel starter 中的自動化配置類生效:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
(3) 配置文件打開
配置文件打開 Sentinel 對 Feign 的支持:
feign.sentinel.enabled=true
示例說明
比如下面的示例中你要了解的:
- 1.正常的業(yè)務調用: /echo/{str}。
- 熔斷后的異常處理,指定了 fallback 處理,并返回 "echo fallback" 字符串。
詳細示例:
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
String echo(@PathVariable("str") String str);
}
class FeignConfiguration {
@Bean
public EchoServiceFallback echoServiceFallback() {
return new EchoServiceFallback();
}
}
class EchoServiceFallback implements EchoService {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
}
1.4 和 RestTemplate 一起使用
支持對 RestTemplate 的服務調用使用 Sentinel 進行保護,加上 @SentinelRestTemplate 注解。
@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
return new RestTemplate();
}
說明:@SentinelRestTemplate 注解的屬性
@SentinelRestTemplate 注解的屬性支持限流(blockHandler, blockHandlerClass)和降級(fallback, fallbackClass)的處理。
比如上面的示例指示了 ExceptionUtil.handleException 是熔斷降級后的異常處理方法,該方面用明確的方法簽名格式,如下:
public class ExceptionUtil {
public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
...
}
}
方法返回值提供了 SentinelClientHttpResponse 用于構造返回信息。
注意
應用啟動的時候會檢查 @SentinelRestTemplate 注解對應的限流或降級方法是否存在,如不存在會拋出異常
實際項目中也會在網(wǎng)關層使用,見下一章節(jié)。
2. 在 Spring Cloud Gateway 網(wǎng)關中使用
可以結合 Spring Cloud Gateway 一起使用。
- (1) 添加 spring-cloud-alibaba-sentinel-gateway 依賴。
- (2) 添加 spring-cloud-starter-gateway 依賴
來讓 spring-cloud-alibaba-sentinel-gateway 模塊里的 Spring Cloud Gateway 自動化配置類生效:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- (3) 配置文件
指定 spring.cloud.sentinel.filter.enabled 為 false
注意:
網(wǎng)關流控規(guī)則數(shù)據(jù)源類型是 gw-flow
,若將網(wǎng)關流控規(guī)則數(shù)據(jù)源指定為 flow 則不生效。
支持兩種資源標識維度的限流
Sentinel 提供的 Spring Cloud Gateway 的適配模塊可以提供兩種資源維度的限流:
- routeId:即在 gateway 中的路由 routeId。
- 自定義分組的名稱:可以利用 API 來自定義一些分組名,將URL歸類在一個組下。
- 默認不支持 URL 粒度
3. sentinel 的控制臺
3.1 Sentinel 控制臺包含如下功能:
- 查看機器列表以及健康情況:收集 Sentinel 客戶端發(fā)送的心跳包,用于判斷機器是否在線。
- 監(jiān)控 (單機和集群聚合):通過 Sentinel 客戶端暴露的監(jiān)控 API,定期拉取并且聚合應用監(jiān)控信息,最終可以實現(xiàn)秒級的實時監(jiān)控。
- 規(guī)則管理和推送:統(tǒng)一管理推送規(guī)則。
- 鑒權:生產(chǎn)環(huán)境中鑒權非常重要。這里每個開發(fā)者需要根據(jù)自己的實際情況進行定制。
3.2. 啟動 sentinel 的控制臺
下載最新版本的控制臺 jar 包
可以從這個 release 頁面 下載。
命令行啟動
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=123456
說明:
- -Dserver.port=8080 用于指定 Sentinel 控制臺端口為 8080,瀏覽器從這個端訪問。打開頁面,默認用戶名和密碼都是 sentinel。
3.3. 規(guī)則管理
管理和新增規(guī)則
打開 http://localhost:8080
您可以在 控制臺web頁 配置修改規(guī)則,進行規(guī)則管理。
點擊新增規(guī)則按鈕,如下:
規(guī)則的存儲
默認是存儲在內(nèi)存的,應用重啟之后該規(guī)則會丟失。建議通過一些配置來使用外部存儲方式來保存。建議結合 nacos 動態(tài)實時的刷新規(guī)則。
3.4. 規(guī)則推送
規(guī)則推送分為 3 種模式,包括:
- 原始模式
- Pull 模式
- Push 模式"。
原始模式
通過 API 將規(guī)則推送至客戶端并直接更新到內(nèi)存中, 圖例:
------> sentinel 客戶端1
Sentinel ------> sentinel 客戶端2
Dashboard
------> sentinel 客戶端3
好處: 簡單,無依賴;
壞處: 應用重啟規(guī)則就會消失,不能用于生產(chǎn)環(huán)境
Pull模式
在客戶端注冊一個本地文件數(shù)據(jù)源:收到控制臺推送的規(guī)則時,Sentinel 會先更新到內(nèi)存,然后將規(guī)則寫入到文件中。
本地文件數(shù)據(jù)源會定時輪詢文件的變更,讀取規(guī)則。
這樣我們既可以在應用本地直接修改文件來更新規(guī)則,也可以通過 Sentinel 控制臺推送規(guī)則。
以本地文件數(shù)據(jù)源為例,過程如下圖所示:
/---------- 在內(nèi)存中更新規(guī)則(規(guī)則緩存)
/
Sentinel -----> Sentinel客戶端 ----> 將規(guī)則寫入本地文件 ----> 本地文件
Dashboard
好處:簡單,不引入新的依賴
壞處:無法保證監(jiān)控數(shù)據(jù)的一致性
Push模式
Sentinel 控制臺 的規(guī)則到 統(tǒng)一配置中心(比如nacos),再到各個 客戶端。
即: Sentinel 控制臺 → 配置中心 → Sentinel 數(shù)據(jù)源 → Sentinel
圖例:
nacos
(1) / \
/ \ (2)
/ \
Sentinel |---- sentinel 客戶端1
Dashboard |---- sentinel 客戶端2
生產(chǎn)環(huán)境建議使用 PUSH 模式,改造方法見下一章節(jié)。
4. 和 nacos 集成
4.1 介紹
默認情況下,規(guī)則是存儲在內(nèi)存的,重啟后就沒了。因此在生產(chǎn)環(huán)境建議使用nacos 集成來使用。分成兩個步驟:
- (1) 在sentinel dashboard 控制臺的web管理頁面創(chuàng)建規(guī)則,并將規(guī)則存儲到nacs。需要改造sentinel 控制臺。
- (2) 客戶端應用獲得從 nacos 推送(PUSH)而來的 “限流的配置規(guī)則”,并加載到sentinel中。
即:在sentinel dashboard 的web頁設置限流規(guī)則 ---> 規(guī)則存儲到 nacos ---> 再推送到客戶端應用
4.2 改造 sentinel 控制臺
改造的目標是:改造 sentinel 控制臺,使得在控制臺的web頁修改的規(guī)則保存到nacos中去。
具體改造方法:略。
有同學已經(jīng)改造好的在這里:https://gitee.com/schonglin/sentinel-nacos
4.3 配置客戶端,讀nacos數(shù)據(jù)源。
實現(xiàn)的目標是:從nacos 讀取規(guī)則并應用到客戶端應用中。
4.3.1 修改客戶端服務的配置文件,添加一個數(shù)據(jù)源
下面的示例中,我添加了一個 sentinel 的數(shù)據(jù)源 ds2, 指定了 nacos服務的地址,data-id 配置文件名,規(guī)則是 rule-type 限流類型。
spring:
application:
name: business
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080 # 指定控制臺地址和端口
port: 8721 # 這個端口和 Sentinel dashborad 做交互
datasource:
# 指定一個用于流控規(guī)則的數(shù)據(jù)源(來自nacos)
ds2:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-flow-rules # 比如流控的規(guī)則是 {appName}-flow-rules
group-id: SENTINEL_GROUP # 指定的一個分組名
data-type: json
rule-type: flow
4.3.2 在nacos中添加一個限流的配置文件,和數(shù)據(jù)源名稱一致
我在nacos中添加一個限流的配置文件,名字叫做${spring.application.name}-sentinel-flow,它的格式和上面 data-id 要對應上。
[
{
"resource": "/hello",
"limitApp": "default",
"grade": 1,
"count": 6,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
上面的配置內(nèi)容說明:
- resource:資源名
- limitApp:調用來源, default 則不區(qū)分調用來源
- grade:限流閾值類型(QPS 或并發(fā)線程數(shù));0代表根據(jù)并發(fā)數(shù)量來限流,1代表根據(jù)QPS來進行流量控制
- count:限流閾值,和上面的類型相關
- strategy:調用關系限流策略
- controlBehavior:流量控制效果(直接拒絕、Warm Up、勻速排隊)
- clusterMode:是否為集群模式
訪問幾次接口后,就可以在Sentinel Dashboard 中看到在nacos中配置的規(guī)則信息,重啟后也可以再次重nacos獲取到配置好的規(guī)則。
我的示例demo 見: https://github.com/vir56k/java_demo/tree/master/sentinel/sentineldemo3 配合 改造后支持nacos的sentinel 來使用。
5. 參考
Sentinel 控制臺
https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8
https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel
https://www.cnblogs.com/gyli20170901/p/11279576.html
https://github.com/alibaba/Sentinel/wiki/Sentinel-%E6%8E%A7%E5%88%B6%E5%8F%B0%EF%BC%88%E9%9B%86%E7%BE%A4%E6%B5%81%E6%8E%A7%E7%AE%A1%E7%90%86%EF%BC%89#%E8%A7%84%E5%88%99%E9%85%8D%E7%BD%AE
https://blog.csdn.net/qq_38723394/article/details/108991518