目錄
-
- 一、前言
- 二、版本選擇和適配
-
- 2.1、本文使用各組件版本
- 2.2、官方推薦版本
- 三、部署sentinel-dashboard
-
- 3.1、下載 sentinel-dashboard jar包
- 3.2、啟動 sentinel-dashboard
- 四、Gateway 集成 Sentinel實現控制臺配置流控規則測試
-
- 4.1、添加Gateway 集成 Sentinel 包
- 4.2、添加 Gateway 服務啟動JVM參數
-
- 4.2.1、配置說明
- 4.2.2、啟動說明
-
- 4.2.2.1、使用 jar 包啟動Gateway添加JVM啟動參數
- 4.2.2.2、IDEA中配置JVM啟動參數(IDEA版本2022.2.1)
- 4.3、啟動 Gateway 注冊到 Sentinel-dashboard 實現接口流控規則動態配置
-
- 4.3.1、啟動 Gateway 注冊到 Sentinel-dashboard
- 4.3.2、通過 Sentinel-dashboard 配置指定接口限流
- 4.4、注意事項
- 五、Gateway 集成 Sentinel 常用配置
-
- 5.1、熱加載
- 5.2、降級處理配置(這里提供代碼配置和使用配置文件配置)
-
- 5.2.1、通過代碼配置(配置文件配置比代碼配置優先級高)
- 5.2.2、通過配置文件配置
- 六、自定義本地加載流控規則
-
- 6.1、通過代碼加載流控規則
- 6.2、通過本地配置文件加載流控規則
-
- 6.2.1、API分組規則json文件編寫(gateway-sentinel-api-groups.json)
- 6.2.2、流控規則json文件編寫(gateway-sentinel-flow-rules.json)
- 6.2.3、配置文件配置加載API分組和流控規則json文件
- 七、動態監聽Nacos規則配置實時更新流控規則實現(推薦)
-
- 7.1、添加sentinel集成nacos包
- 7.2、Nacos配置中心添加API分組規則json(gateway-sentinel-api-groups)
- 7.3、Nacos配置中心添加流控規則json(gateway-sentinel-flow-rules)
- 7.4、配置文件配置加載Nacos配置中心API分組和流控規則json
- 7.5、測試效果
一、前言
Sentinel 是 SpringCloud Alibaba 家族的服務保護組件,很多項目在前中期沒有遇到流量突增不太注意服務保護的重要性,當流量突增打爆應用服務或數據庫時束手無策,可以不配置流控規則,但是需要時一定可以熱加載使用,本文會對集成Sentinel以及動態拉取Nacos配置規則實現熱加載流控規則進行講解。
官網地址
二、版本選擇和適配
使用 SpringCloud Alibaba 家族組件,要注意一下版本兼容問題,避免出現一些奇怪的問題,這里會說明本文使用的各組件版本,以及 SpringCloud Alibaba 推薦的各版本適配。
2.1、本文使用各組件版本
部分組件對版本兼容要求其實沒有那么高,比如Nacos,不一定要按照官方推薦版本,差幾個小版本沒有什么影響,我本地使用的一直是Nacos2.0.2,代碼集成實現基本都一樣。
JDK:1.8.0
Spring-Boot:2.3.12.RELEASE
Spring-Cloud:Hoxton.SR12
Spring-Cloud-Alibaba:2.2.9.RELEASE
Nacos:2.0.2
Sentinel:1.8.5
2.2、官方推薦版本
官方版本說明
三、部署sentinel-dashboard
3.1、下載 sentinel-dashboard jar包
這里使用sentinel-dashboard-1.8.5,這里提供兩個下載地址,需要其它版本可以自行去github下載。
github下載地址
百度網盤地址
3.2、啟動 sentinel-dashboard
java -Dserver.port=8180 -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=123456 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.5.jar
- -Dserver.port=8180
sentine 服務控制臺端口 - -Dsentinel.dashboard.auth.username=sentinel
sentine 控制臺登錄賬號,不設置默認sentinel - -Dsentinel.dashboard.auth.password=123456
sentine 控制臺登錄密碼,不設置默認sentinel - -Dcsp.sentinel.dashboard.server=localhost:8180
將控制臺自身注冊到server - -Dproject.name=sentinel-dashboard
控制臺服務自己項目名稱
四、Gateway 集成 Sentinel實現控制臺配置流控規則測試
4.1、添加Gateway 集成 Sentinel 包
在原有網關項目基礎上添加上這兩個包,這兩個包會將gateway集成sentinel,并且默認是自動配置的,無需手動配置。
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>
4.2、添加 Gateway 服務啟動JVM參數
4.2.1、配置說明
Gateway 連接 Sentinel 控制臺的配置,Sentinel1.7.0 版本以下不支持配置文件配置,推薦直接使用JVM參數配置。
-
添加JVM啟動參數:
-Dcsp.sentinel.dashboard.server=127.0.0.1:8180
-Dcsp.sentinel.api.port=18719
-Dproject.name=kerwin-gateway
-Dcsp.sentinel.app.type=1 -
參數說明:
-Dcsp.sentinel.dashboard.server:指定控制臺地址和端口。
-Dproject.name:在sentinel控制臺中展示的項目名稱。
-Dcsp.sentinel.api.port:指定客戶端監控 API 的端口(默認是 8719),如控制臺修改規則,則會向該端口推送規則信息。
-Dcsp.sentinel.app.type:從 1.6.3 版本開始,控制臺支持網關流控規則管理。該啟動參數設置成1會將您的服務標記為 API Gateway,在接入控制臺時您的服務會自動注冊為網關類型,然后您即可在控制臺配置網關規則和 API 分組。
4.2.2、啟動說明
這里提供服務打成jar包啟動和使用IDEA開發工具添加JVM參數啟動示例。
4.2.2.1、使用 jar 包啟動Gateway添加JVM啟動參數
java -Dcsp.sentinel.dashboard.server=127.0.0.1:8180 -Dcsp.sentinel.api.port=18719 -Dproject.name=kerwin-gateway -Dcsp.sentinel.app.type=1 -jar kerwin-gateway.jar
4.2.2.2、IDEA中配置JVM啟動參數(IDEA版本2022.2.1)
不同版本IDEA可以配置入口不同,有需要可以自己查詢
4.3、啟動 Gateway 注冊到 Sentinel-dashboard 實現接口流控規則動態配置
這里需要注意,Gateway 集成 Sentinel-dashboard 默認是懶加載的
,需要調用一次接口才能注冊到 Sentinel-dashboard,也可以直接在 Gateway 中配置成熱加載,添加spring.cloud.sentinel.eager:true
實現服務器啟動了自動心跳注冊。
4.3.1、啟動 Gateway 注冊到 Sentinel-dashboard
4.3.2、通過 Sentinel-dashboard 配置指定接口限流
這里需要注意,這個流控規則是按照組級別來的,一個組內所有匹配規則會共用一個閾值,如果需要在網關應用配置單獨接口流控規則目前來看只能配置多個分組,然后單獨配置規則。
-
1、新增 API 分組
-
2、自定義分組內 API 匹配規則
-
3、新增網關流控規則
-
4、配置網關流控規則(這里需要注意,這個流控規則是按照組級別來的,一個組內所有匹配規則共用一個閾值)
-
5、測試限流規則
快速請求兩次可以看到服務端響應Blocked by Sentinel: ParamFlowException
,響應內容也是可以自定義的,這個會在后面說明。
PS:1秒內同時請求一次 /user/info
接口 和 /user/list
接口,也會響應Blocked by Sentinel: ParamFlowException
,因為同一個分組共用一個閾值,如果要單獨配置某一個接口目前看只能整多個分組。
4.4、注意事項
需要注意:如果不做特殊處理,通過Sentinel控制臺配置的規則在應用服務重啟后就沒了,通過Sentinel控制臺配置流控規則的本質其實就是將編輯好的規則加載到應用服務緩存中,并不會進行持久化,如果想要持久化Sentinel控制臺配置的規則需要特殊處理,后續會進行說明。
五、Gateway 集成 Sentinel 常用配置
5.1、熱加載
spring:cloud:sentinel:# 設置sentinel為熱加載 默認為falseeager: true
5.2、降級處理配置(這里提供代碼配置和使用配置文件配置)
5.2.1、通過代碼配置(配置文件配置比代碼配置優先級高)
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;@Configuration
public class SentinelGatewayConfiguration {/*** 自定義降級處理響應*/@PostConstructpublic void init(){GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable throwable) {return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).bodyValue("{"code":500,"msg":"代碼配置-被限流了!"}");}});}
}
5.2.2、通過配置文件配置
spring:cloud:sentinel:# 設置sentinel為熱加載 默認為falseeager: truescg:# 降級處理配置 也可以在代碼中實現fallback:# 指定降級處理的模式為返回響應,也可以配置成重定向redirect,配置重定向需要指定重定向地址mode: 'response'response-status: 200response-body: '{"code":500,"msg":"配置文件配置-被限流了!"}'# mode 為 redirect 時使用redirect: 'https://blog.csdn.net/weixin_44606481'
六、自定義本地加載流控規則
因為 sentinel-dashboard
不會持久化手動配置的流控規則,一般情況下我們都會提前配置一些我們需要的規則,可以通過代碼或者配置文件配置。
6.1、通過代碼加載流控規則
Sentinel
的API管理存儲在 GatewayApiDefinitionManager
類中,流控規則存儲在 GatewayRuleManager
類中,添加好自己需要的配置即可。
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.Set;@Configuration
public class SentinelGatewayRuleConfiguration {@PostConstructpublic void initRule(){// 加載根據路由 ID 配置限流規則this.initGatewayFlowRules();// 加載根據API分組配置限流規則this.initApiDefinitions();}private void initGatewayFlowRules() {// 存儲限流規則的集合Set<GatewayFlowRule> rules = GatewayRuleManager.getRules();if(rules == null){rules = new HashSet<>();}// 根據路由 ID 配置限流規則GatewayFlowRule rule1 = new GatewayFlowRule("kerwin-user").setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID).setCount(1) // QPS閾值.setIntervalSec(1); // 間隔rules.add(rule1);// 加載限流規則GatewayRuleManager.loadRules(rules);}private void initApiDefinitions() {Set<ApiDefinition> apiDefinitions = GatewayApiDefinitionManager.getApiDefinitions();if(apiDefinitions == null){apiDefinitions = new HashSet<>();}// 創建一個 API 分組ApiDefinition apiDefinition1 = new ApiDefinition("user服務API組");// API 分組 URL 匹配規則Set<ApiPredicateItem> apiPathPredicateItems = new HashSet<>();// 添加精確匹配 匹配為 /api-user/user/info 的urlapiPathPredicateItems.add(new ApiPathPredicateItem().setPattern("/api-user/user/info").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT));// 添加前綴匹配 用于匹配以 /api-user/user 開頭的URLapiPathPredicateItems.add(new ApiPathPredicateItem().setPattern("/api-user/user/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
// // 添加正則匹配 用于匹配以 list 結尾的 URL
// apiPathPredicateItems.add(new ApiPathPredicateItem().setPattern("^.*list$")
// .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_REGEX));apiDefinition1.setPredicateItems(apiPathPredicateItems);apiDefinitions.add(apiDefinition1);// 根據 API 分組配置限流規則Set<GatewayFlowRule> rules = GatewayRuleManager.getRules();if(rules == null){rules = new HashSet<>();}GatewayFlowRule rule1 = new GatewayFlowRule(apiDefinition1.getApiName()).setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME).setCount(1) // QPS閾值.setIntervalSec(1); // 間隔rules.add(rule1);// 加載 API 分組定義GatewayApiDefinitionManager.loadApiDefinitions(apiDefinitions);// 加載限流規則GatewayRuleManager.loadRules(rules);}
}
項目啟動后可以在Sentinel
控制臺看到代碼配置的API分組和流控規則。
6.2、通過本地配置文件加載流控規則
通過代碼手動配置會比較麻煩而且不易調整,Gateway
集成Sentinel
包提供了通過配置文件加載API分組和流控規則實現,這里會將API分組和流控規則都分別寫入不同的json
文件中,交由對于實現類去進行加載。
6.2.1、API分組規則json文件編寫(gateway-sentinel-api-groups.json)
在resource
目錄創建gateway-sentinel-api-groups.json
將API分組規則內容填進去。
[{"apiName": "user服務API組","predicateItems": [{"pattern": "/api-user/user/info","matchStrategy": 0},{"pattern": "/api-user/user/**","matchStrategy": 1}]}
]
解釋:
- apiName:
字符串,代表 API 組名稱,這里是 “user服務API組”,用于統一管理相關 API。 - predicateItems:
數組,包含多個 predicateItem 對象,用于描述 API 的匹配模式。 - predicateItem 內部元素:
- pattern:
字符串,使用不同風格的表達式。
例如,“/api-user/user/info” 精確匹配該路徑;“/api-user/user/**” 匹配 /api-user/user/ 下的所有路徑(包括子路徑)。 - matchStrategy:
整數,匹配策略:
0:精確匹配,路徑需與 pattern 完全一致。
1:前綴匹配,路徑以 pattern 開頭即可。
2:正則匹配,使用 pattern 作為正則表達式進行匹配。
- pattern:
6.2.2、流控規則json文件編寫(gateway-sentinel-flow-rules.json)
在resource
目錄創建gateway-sentinel-flow-rules.json
將流控規則內容填進去。
[{"resource": "user服務API組","resourceMode": 1,"count": 1,"intervalSec": 1,"burst": 0,"paramItem": null,"controlBehavior": 0,"maxQueueingTimeoutMs": 0},{"resource": "kerwin-user","resourceMode": 0,"count": 1,"intervalSec": 1,"burst": 0,"paramItem": null,"controlBehavior": 0,"maxQueueingTimeoutMs": 0}
]
字段解釋:
- resource:資源名稱,用于標識要進行流控的目標。可以是路由 ID、自定義 API 分組名稱等。在網關場景中,資源可以代表一個具體的路由或者一組路由的集合。
- resourceMode:
- 0:代表資源模式,對應 SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID,表示基于 Route ID 進行資源匹配。
- 1:API分組模式,對應 SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME,標識基于API分組進行資源匹配。
- count:流控閾值,根據 grade 字段的不同,其代表的意義也不同。如果 grade 為 QPS 限流,count 表示每秒允許通過的請求數量;如果 grade 為并發線程數限流,count 表示允許的最大并發線程數。
- grade:流控閾值類型,取值有兩種。1 表示 QPS(每秒查詢率)限流,0 表示并發線程數限流。
- intervalSec:統計時間窗口,單位為秒。表示在多長時間內統計請求數量以判斷是否觸發流控。
- controlBehavior:流控效果,即當請求超過閾值時的處理方式
- 0:快速失敗,請求超過閾值時直接拒絕并拋出異常
- 2:勻速排隊,請求會進入隊列,按照固定速率處理,避免流量突發
- burst:僅在 controlBehavior 為 0(快速失敗)時有效,表示突發流量容忍值。在短時間內允許超過閾值的額外請求數量,用于應對突發流量場景。
- maxQueueingTimeoutMs:僅在 controlBehavior 為 2(勻速排隊)時有效,表示請求在隊列中的最大排隊時間,單位為毫秒。超過該時間的請求將被拒絕。
6.2.3、配置文件配置加載API分組和流控規則json文件
在配置文件中添加API分組和流控規則讀取數據源配置,這里省略了其它Sentinel
配置需要可以看之前配置內容添加。
spring:cloud:sentinel:# 設置sentinel為熱加載 默認為falseeager: true# API分組&流控規則配置文件配置datasource:ds1:file:file: classpath:gateway-sentinel-api-groups.jsonruleType: gw-api-group # 網關API分組dataType: jsonds2:file:file: classpath:gateway-sentinel-flow-rules.jsonruleType: gw-flow # 網關流控規則dataType: json
這里就不貼圖了,配置完成后啟動看看Sentinel
控制臺是否有初始化這些配置,要記得開啟熱加載。
七、動態監聽Nacos規則配置實時更新流控規則實現(推薦)
通過Nacos
配置中心動態拉取加載流控規則和本地配置文件配置是類似的,編寫的規則json
是一樣的,只是需要指定一下加載的數據源為Nacos
讀取,并且已經實現了動態加載,在Nacos
配置中心修改規則會進行實時同步。
7.1、添加sentinel集成nacos包
sentinel
讀取nacos
配置需要添加這個適配包。
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>
7.2、Nacos配置中心添加API分組規則json(gateway-sentinel-api-groups)
配置的內容和本文6.2.1
中一致。
7.3、Nacos配置中心添加流控規則json(gateway-sentinel-flow-rules)
配置的內容和本文6.2.2
中一致。
7.4、配置文件配置加載Nacos配置中心API分組和流控規則json
spring:cloud:sentinel:# 設置sentinel為熱加載 默認為falseeager: true# API分組&流控規則配置文件配置datasource:ds1:nacos:server-addr: 172.16.8.169:8848data-id: gateway-sentinel-api-groupsnamespace: springcloud-component-examplegroup-id: DEFAULT_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: gw-api-groupds2:nacos:server-addr: 172.16.8.169:8848data-id: gateway-sentinel-flow-rulesnamespace: springcloud-component-examplegroup-id: DEFAULT_GROUPusername: nacospassword: nacosdata-type: jsonrule-type: gw-flow
7.5、測試效果
- 1、啟動網關服務,查看注冊API分組和流控規則
- 2、Nacos配置中心修改流控規則
- 3、查看sentinel控制臺同步情況