1 Sentinel主頁
https://github.com/alibaba/Sentinel/wiki/主頁
1.1 Sentinel介紹
隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 是面向分散式服務架構的流量控制元件,主要以流量為切入點,從限流、流量整形、熔斷降級、系統負載保護、熱點防護等多個維度來幫助開發者保障微服務的穩定性。
1)Sentinel核心元件
1:核心庫(Java 客戶端):不依賴任何框架/庫,能夠執行於 Java 7 及以上的版本的執行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支援。
2:控制檯(Dashboard):控制檯主要負責管理推送規則、監控、叢集限流分配管理、機器發現等。
2)Sentinel vs Hystrix
對比內容 | Sentinel | Hystrix |
---|---|---|
隔離策略 | 訊號量隔離 | 執行緒池隔離/訊號量隔離 |
熔斷降級策略 | 基於響應時間或失敗比率 | 基於失敗比率 |
實時指標實現 | 滑動視窗 | 滑動視窗(基於 RxJava) |
規則配置 | 支援多種資料來源 | 支援多種資料來源 |
擴充套件性 | 多個擴充套件點 | 外掛的形式 |
基於註解的支援 | 支援 | 支援 |
限流 | 基於 QPS,支援基於呼叫關係的限流 | 不支援 |
流量整形 | 支援慢啟動、勻速器模式 | 不支援 |
系統負載保護 | 支援 | 不支援 |
控制檯 | 開箱即用,可配置規則、檢視秒級監控、機器發現等 | 不完善 |
常見框架的適配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
3)Sentinel基本概念
- 資源
資源是 Sentinel 的關鍵概念。它可以是 Java 應用程式中的任何內容,例如,由應用程式提供的服務,或由應用程式呼叫的其它應用提供的服務,甚至可以是一段程式碼。
只要通過 Sentinel API 定義的程式碼,就是資源,能夠被 Sentinel 保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作為資源名來標示資源。
- 規則
圍繞資源的實時狀態設定的規則,可以包括流量控制規則、熔斷降級規則以及系統保護規則。所有規則可以動態實時調整。
1.2 Sentinel核心功能
1.2.1 流量控制
流量控制在網路傳輸中是一個常用的概念,它用於調整網路包的傳送資料。然而,從系統穩定性角度考慮,在處理請求的速度上,也有非常多的講究。任意時間到來的請求往往是隨機不可控的,而系統的處理能力是有限的。我們需要根據系統的處理能力對流量進行控制。Sentinel 作為一個調配器,可以根據需要把隨機的請求調整成合適的形狀,如下圖所示:
流量控制有以下幾個角度:
- 資源的呼叫關係,例如資源的呼叫鏈路,資源和資源之間的關係;
- 執行指標,例如 QPS、執行緒池、系統負載等;
- 控制的效果,例如直接限流、冷啟動、排隊等。
Sentinel 的設計理念是讓您自由選擇控制的角度,並進行靈活組合,從而達到想要的效果。
1.2.2 熔斷降級
1)什麼是熔斷降級
除了流量控制以外,及時對呼叫鏈路中的不穩定因素進行熔斷也是 Sentinel 的使命之一。由於呼叫關係的複雜性,如果呼叫鏈路中的某個資源出現了不穩定,可能會導致請求發生堆積,進而導致級聯錯誤。
Sentinel 和 Hystrix 的原則是一致的: 當檢測到呼叫鏈路中某個資源出現不穩定的表現,例如請求響應時間長或異常比例升高的時候,則對這個資源的呼叫進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯故障。
2)Sentinel熔斷降級設計
Hystrix 通過 執行緒池隔離 的方式,來對依賴(在 Sentinel 的概念中對應 資源)進行了隔離。這樣做的好處是資源和資源之間做到了最徹底的隔離。缺點是除了增加了執行緒切換的成本(過多的執行緒池導致執行緒數目過多),還需要預先給各個資源做執行緒池大小的分配。
Sentinel熔斷降級設計:
併發執行緒數限制:和資源池隔離的方法不同,Sentinel 通過限制資源併發執行緒的數量,來減少不穩定資源對其它資源的影響。這樣不但沒有執行緒切換的損耗,也不需要您預先分配執行緒池的大小。當某個資源出現不穩定的情況下,例如響應時間變長,對資源的直接影響就是會造成執行緒數的逐步堆積。當執行緒數在特定資源上堆積到一定的數量之後,對該資源的新請求就會被拒絕。堆積的執行緒完成任務後才開始繼續接收請求。
響應時間降級:除了對併發執行緒數進行控制以外,Sentinel 還可以通過響應時間來快速降級不穩定的資源。當依賴的資源出現響應時間過長後,所有對該資源的訪問都會被直接拒絕,直到過了指定的時間視窗之後才重新恢復。
3)系統自適應保護
Sentinel 同時提供系統維度的自適應保護能力。防止雪崩,是系統防護中重要的一環。當系統負載較高的時候,如果還持續讓請求進入,可能會導致系統崩潰,無法響應。在叢集環境下,網路負載均衡會把本應這臺機器承載的流量轉發到其它的機器上去。如果這個時候其它的機器也處在一個邊緣狀態的時候,這個增加的流量就會導致這臺機器也崩潰,最後導致整個叢集不可用。
針對這個情況,Sentinel 提供了對應的保護機制,讓系統的入口流量和系統的負載達到一個平衡,保證系統在能力範圍之內處理最多的請求。
Sentinel整合Gateway
我們的專案流量入口是SpringCloud Gateway
,因此我們重點講解Sentinel整合Gateway
。
3.1 Sentinel對閘道器支援
Sentinel 支援對 Spring Cloud Gateway、Zuul 等主流的 API Gateway 進行限流。
Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common
模組,此模組中包含閘道器限流的規則和自定義 API 的實體和管理邏輯
從 1.6.0 版本開始,Sentinel 提供了 Spring Cloud Gateway 的適配模組,可以提供兩種資源維度的限流:
-
route 維度:即在 Spring 配置檔案中配置的路由條目,資源名為對應的 routeId
spring: gateway: #路由配置 routes: #唯一識別符號 - id: hailtaxi-driver uri: lb://hailtaxi-driver #路由斷言 predicates: - Path=/driver/** #唯一識別符號 - id: hailtaxi-order uri: lb://hailtaxi-order #路由斷言 predicates: - Path=/order/**
自動將每個路由標識為資源,
-
自定義 API 維度:使用者可以利用 Sentinel 提供的 API 來自定義一些 API 分組
這兩種維度分別對應如下:
-
GatewayFlowRule:閘道器限流規則,針對 API Gateway 的場景定製的限流規則,可以針對不同 route 或自定義的 API 分組進行限流,支援針對請求中的引數、Header、來源 IP 等進行定製化的限流。
-
ApiDefinition:使用者自定義的 API 定義分組,可以看做是一些 URL 匹配的組合。比如我們可以定義一個 API 叫
my_api
,請求 path 模式為/foo/**
和/baz/**
的都歸到my_api
這個 API 分組下面。限流的時候可以針對這個自定義的 API 分組維度進行限流。
其中閘道器限流規則 GatewayFlowRule
的欄位解釋如下:
-
resource
:資源名稱,可以是閘道器中的 route 名稱或者使用者自定義的 API 分組名稱。 -
resourceMode
:規則是針對 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID
)還是使用者在Sentinel
中定義的 API 分組(RESOURCE_MODE_CUSTOM_API_NAME
),預設是 route。 -
grade
:限流指標維度,同限流規則的grade
欄位。 -
count
:限流閾值 -
intervalSec
:統計時間視窗,單位是秒,預設是 1 秒。 -
controlBehavior
:流量整形的控制效果,同限流規則的controlBehavior
欄位,目前支援快速失敗和勻速排隊兩種模式,預設是快速失敗。 -
burst
:應對突發請求時額外允許的請求數目。 -
maxQueueingTimeoutMs
:勻速排隊模式下的最長排隊時間,單位是毫秒,僅在勻速排隊模式下生效。 -
paramItem
:引數限流配置。若不提供,則代表不針對引數進行限流,該閘道器規則將會被轉換成普通流控規則;否則會轉換成熱點規則。其中的欄位: -
parseStrategy
:從請求中提取引數的策略,目前支援提取來源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP
)、Host(PARAM_PARSE_STRATEGY_HOST
)、任意 Header(PARAM_PARSE_STRATEGY_HEADER
)和任意 URL 引數(PARAM_PARSE_STRATEGY_URL_PARAM
)四種模式。fieldName
:若提取策略選擇 Header 模式或 URL 引數模式,則需要指定對應的 header 名稱或 URL 引數名稱。
-
pattern
:引數值的匹配模式,只有匹配該模式的請求屬性值會納入統計和流控;若為空則統計該請求屬性的所有值。(1.6.2 版本開始支援)matchStrategy
:引數值的匹配策略,目前支援精確匹配(PARAM_MATCH_STRATEGY_EXACT
)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS
)和正則匹配(PARAM_MATCH_STRATEGY_REGEX
)。(1.6.2 版本開始支援)
使用者可以通過 GatewayRuleManager.loadRules(rules)
手動載入閘道器規則,或通過 GatewayRuleManager.register2Property(property)
註冊動態規則源動態推送(推薦方式)。
3.2 GateWay整合Sentinel
我們如果想要讓微服務閘道器整合Sentinel,需要引入依賴包,使用時只需注入對應的 SentinelGatewayFilter
例項以及 SentinelGatewayBlockExceptionHandler
例項即可。
1、首先在hailtaxi-gateway
中引入如下依賴:
<!--Sentinel-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.8.0</version>
</dependency>
2、例項引入:建立配置類com.itheima.config.GatewayConfiguration
:
package com.itheima.config;
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.GatewayParamFlowItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
/**
* 限流的異常處理器
* @return
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
/***
* Sentinel路由處理核心過濾器
* @return
*/
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
public void doInit() {
// 自定義 api 分組
initCustomizedApis();
// 初始化閘道器流控規則
initGatewayRules();
}
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("customer_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/order/**")
/**
* 匹配策略:
* URL_MATCH_STRATEGY_EXACT:url精確匹配
* URL_MATCH_STRATEGY_PREFIX:url字首匹配
* URL_MATCH_STRATEGY_REGEX:url正則匹配
*/
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("hailtaxi-driver") // 資源名稱,可以是閘道器中的 routeid或者使用者自定義的 API分組名稱
.setCount(2) // 限流閾值
.setIntervalSec(10) // 統計時間視窗預設1s
.setGrade(RuleConstant.FLOW_GRADE_QPS) // 限流模式
/**
* 限流行為:
* CONTROL_BEHAVIOR_RATE_LIMITER 勻速排隊
* CONTROL_BEHAVIOR_DEFAULT 快速失敗(預設)
* CONTROL_BEHAVIOR_WARM_UP:
* CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
*/
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
//勻速排隊模式下的最長排隊時間,單位是毫秒,僅在勻速排隊模式下生效
.setMaxQueueingTimeoutMs(1000)
/**
* 熱點引數限流配置
* 若不設定,該閘道器規則將會被轉換成普通流控規則;否則會轉換成熱點規則
*/
.setParamItem(new GatewayParamFlowItem()
/**
* 從請求中提取引數的策略:
* PARAM_PARSE_STRATEGY_CLIENT_IP
* PARAM_PARSE_STRATEGY_HOST
* PARAM_PARSE_STRATEGY_HEADER
* PARAM_PARSE_STRATEGY_URL_PARAM
*/
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER)
/**
* 若提取策略選擇 Header 模式或 URL 引數模式,
* 則需要指定對應的 header 名稱或 URL 引數名稱。
*/
.setFieldName("token")
/**
* 引數的匹配策略:
* PARAM_MATCH_STRATEGY_EXACT
* PARAM_MATCH_STRATEGY_PREFIX
* PARAM_MATCH_STRATEGY_REGEX
* PARAM_MATCH_STRATEGY_CONTAINS
*/
.setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_EXACT)
//引數值的匹配模式,只有匹配該模式的請求屬性值會納入統計和流控
.setPattern("123456") // token=123456 10s內qps達到2次會被限流
)
);
rules.add(new GatewayFlowRule("customer_api")
/**
* 規則是針對 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)
* 還是使用者在 Sentinel 中定義的 API 分組(RESOURCE_MODE_CUSTOM_API_NAME),預設是 route。
*/
.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
.setCount(2)
.setIntervalSec(1)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
);
GatewayRuleManager.loadRules(rules);
}
}
此時整合就完成了。
3、啟動hailtaxi-gateway
,hailtaxi-drvier
,hailtaxi-order
測試:
使用postman測試,
請求:http://localhost:8001/driver/info/1
10秒內請求超過2次會被限流
請求:localhost:8001/order
1秒內qps達到2次會被限流
本文由傳智教育博學谷 - 狂野架構師教研團隊釋出
轉載請註明出處!