目錄
Spring Cloud Alibaba | Sentinel: 服務限流基礎篇
Springboot: 2.1.6.RELEASE
SpringCloud: Greenwich.SR1
如無特殊說明,本系列文章全採用以上版本
上一篇《Spring Cloud Alibaba | Sentinel: 分散式系統的流量防衛兵初探》我們介紹了Sentinel是什麼,並且做了一個簡單的Demo來驗證服務限流。
這一篇,我們主要講什麼是服務限流,包括Sentinel支援的限流方式。
在講服務限流之前,我們先了解什麼是資源。
1. 簡介
資源:可以是任何東西,服務,服務裡的方法,甚至是一段程式碼。使用 Sentinel 來進行資源保護,主要分為幾個步驟:
定義資源
定義規則
檢驗規則是否生效
先把可能需要保護的資源定義好,之後再配置規則。也可以理解為,只要有了資源,我們就可以在任何時候靈活地定義各種流量控制規則。在編碼的時候,只需要考慮這個程式碼是否需要保護,如果需要保護,就將之定義為一個資源。
2. 定義資源
2.1 主流框架的預設適配
為了減少開發的複雜程度,Sentinel對大部分的主流框架,例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了適配。
2.1.1 Web Servlet
Sentinel 提供與 Servlet 的整合,可以對 Web 請求進行流量控制。使用時需引入以下模組(以 Maven 為例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>x.y.z</version>
</dependency>
僅需要在 Web 容器中的 web.xml 配置檔案中進行如下配置即可開啟 Sentinel 支援:
<filter>
<filter-name>SentinelCommonFilter</filter-name>
<filter-class>com.alibaba.csp.sentinel.adapter.servlet.CommonFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SentinelCommonFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
若是 Spring 應用可以通過 Spring 進行配置,例如:
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
registration.setName("sentinelFilter");
registration.setOrder(1);
return registration;
}
}
預設情況下,當請求被限流時會返回預設的提示頁面。您也可以通過 WebServletConfig.setBlockPage(blockPage)
方法設定自定義的跳轉 URL,當請求被限流時會自動跳轉至設定好的 URL。同樣也可以實現 UrlBlockHandler
介面並編寫定製化的限流處理邏輯,然後將其註冊至 WebCallbackManager
中。
注意: Sentinel Web Filter 會將每個到來的不同的 URL 都作為不同的資源處理,因此對於 REST 風格的 API,需要自行實現 UrlCleaner 介面清洗一下資源(比如將滿足 /foo/:id
的 URL 都歸到 /foo/*
資源下),然後將其註冊至 WebCallbackManager
中。否則會導致資源數量過多,超出資源數量閾值(目前是 6000
)時多出的資源的規則將 不會生效。
2.1.2 Dubbo
Sentinel 提供 Dubbo 的相關適配 Sentinel Dubbo Adapter,主要包括針對 Service Provider 和 Service Consumer 實現的 Filter。相關模組:
sentinel-apache-dubbo-adapter(相容 Apache Dubbo 2.7.x 及以上版本,自 Sentinel 1.5.1 開始支援)
sentinel-dubbo-adapter(相容 Dubbo 2.6.x 版本)
對於 Apache Dubbo 2.7.x 及以上版本,使用時需引入以下模組(以 Maven 為例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>x.y.z</version>
</dependency>
對於 Dubbo 2.6.x 及以下版本,使用時需引入以下模組(以 Maven 為例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>x.y.z</version>
</dependency>
引入此依賴後,Dubbo 的服務介面和方法(包括呼叫端和服務端)就會成為 Sentinel 中的資源,在配置了規則後就可以自動享受到 Sentinel 的防護能力。
若不希望開啟 Sentinel Dubbo Adapter 中的某個 Filter,可以手動關閉對應的 Filter,比如:
<!-- 關閉 Sentinel 對應的 Service Consumer Filter -->
<dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/>
限流粒度可以是服務介面和服務方法兩種粒度:
服務介面:resourceName 為 介面全限定名,如 com.alibaba.csp.sentinel.demo.dubbo.FooService
服務方法:resourceName 為 介面全限定名:方法簽名,如 com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)
2.1.3 Spring Cloud
引入依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
下面這個例子就是一個最簡單的使用 Sentinel 的例子:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
@RestController
public class TestController {
@GetMapping(value = "/hello")
@SentinelResource("hello")
public String hello() {
return "Hello Sentinel";
}
}
@SentinelResource
註解用來標識資源是否被限流、降級。上述例子上該註解的屬性 'hello' 表示資源名。
@SentinelResource
用於定義資源,並提供可選的異常處理和 fallback 配置項。 @SentinelResource 註解包含以下屬性:
value
:資源名稱,必需項(不能為空)entryType
:entry
型別,可選項(預設為EntryType.OUT
)blockHandler
/blockHandlerClass
:blockHandler
對應處理BlockException
的函式名稱,可選項。blockHandler
函式訪問範圍需要是public
,返回型別需要與原方法相匹配,引數型別需要和原方法相匹配並且最後加一個額外的引數,型別為BlockException
。blockHandler
函式預設需要和原方法在同一個類中。若希望使用其他類的函式,則可以指定blockHandlerClass
為對應的類的Class
物件,注意對應的函式必需為static
函式,否則無法解析。fallback
:fallback
函式名稱,可選項,用於在丟擲異常的時候提供fallback
處理邏輯。fallback
函式可以針對所有型別的異常(除了exceptionsToIgnore
裡面排除掉的異常型別)進行處理。fallback
函式簽名和位置要求:返回值型別必須與原函式返回值型別一致;
方法引數列表需要和原函式一致,或者可以額外多一個
Throwable
型別的引數用於接收對應的異常;fallback
函式預設需要和原方法在同一個類中。若希望使用其他類的函式,則可以指定fallbackClass
為對應的類的Class
物件,注意對應的函式必需為static
函式,否則無法解析。
defaultFallback
(since 1.6.0):預設的fallback
函式名稱,可選項,通常用於通用的fallback
邏輯(即可以用於很多服務或方法)。預設fallback
函式可以針對所有型別的異常(除了exceptionsToIgnore
裡面排除掉的異常型別)進行處理。若同時配置了fallback
和defaultFallback
,則只有fallback
會生效。defaultFallback
函式簽名要求:返回值型別必須與原函式返回值型別一致;
方法引數列表需要為空,或者可以額外多一個
Throwable
型別的引數用於接收對應的異常。defaultFallback
函式預設需要和原方法在同一個類中。若希望使用其他類的函式,則可以指定fallbackClass
為對應的類的Class
物件,注意對應的函式必需為static
函式,否則無法解析。
exceptionsToIgnore
(since 1.6.0):用於指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣丟擲。
特別地,若 blockHandler
和 fallback
都進行了配置,則被限流降級而丟擲 BlockException
時只會進入 blockHandler
處理邏輯。若未配置 blockHandler
、fallback
和 defaultFallback
,則被限流降級時會將 BlockException
直接丟擲。
示例:
public class TestService {
// 對應的 `handleException` 函式需要位於 `ExceptionUtil` 類中,並且必須為 static 函式.
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
public void test() {
System.out.println("Test");
}
// 原函式
@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
public String hello(long s) {
return String.format("Hello at %d", s);
}
// Fallback 函式,函式簽名與原函式一致或加一個 Throwable 型別的引數.
public String helloFallback(long s) {
return String.format("Halooooo %d", s);
}
// Block 異常處理函式,引數最後多一個 BlockException,其餘與原函式一致.
public String exceptionHandler(long s, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
}
從 1.4.0 版本開始,註解方式定義資源支援自動統計業務異常,無需手動呼叫 Tracer.trace(ex) 來記錄業務異常。Sentinel 1.4.0 以前的版本需要自行呼叫 Tracer.trace(ex) 來記錄業務異常。
AspectJ
如果應用直接使用了 AspectJ,那麼需要在 aop.xml 檔案中引入對應的 Aspect:
<aspects>
<aspect name="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"/>
</aspects>
Spring AOP
如果應用使用了 Spring AOP,需要通過配置的方式將 SentinelResourceAspect 註冊為一個 Spring Bean:
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
2.1.4 Spring WebFlux
注:從 1.5.0 版本開始支援,需要 Java 8 及以上版本。
Sentinel 提供與 Spring WebFlux 的整合模組,從而 Reactive Web 應用也可以利用 Sentinel 的流控降級來保障穩定性。該整合模組基於 Sentinel Reactor Adapter 實現。
使用時需引入以下模組(以 Maven 為例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-webflux-adapter</artifactId>
<version>x.y.z</version>
</dependency>
使用時只需注入對應的 SentinelWebFluxFilter 例項以及 SentinelBlockExceptionHandler 例項即可。比如:
@Configuration
public class WebFluxConfig {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public WebFluxConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(-1)
public SentinelBlockExceptionHandler sentinelBlockExceptionHandler() {
// Register the block exception handler for Spring WebFlux.
return new SentinelBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public SentinelWebFluxFilter sentinelWebFluxFilter() {
// Register the Sentinel WebFlux filter.
return new SentinelWebFluxFilter();
}
}
您可以在 WebFluxCallbackManager
註冊回撥進行定製:
setBlockHandler
:註冊函式用於實現自定義的邏輯處理被限流的請求,對應介面為BlockRequestHandler
。預設實現為DefaultBlockRequestHandler
,當被限流時會返回類似於下面的錯誤資訊:Blocked by Sentinel: FlowException
。setUrlCleaner
:註冊函式用於Web
資源名的歸一化。函式型別為(ServerWebExchange, String) → String
,對應含義為(webExchange, originalUrl) → finalUrl
。setRequestOriginParser
:註冊函式用於從請求中解析請求來源。函式型別為ServerWebExchange → String
。
2.1.5 gRPC
Sentinel 提供與 gRPC Java 的整合,以 gRPC ServerInterceptor 和 ClientInterceptor 的形式保護 gRPC 服務資源。
使用時需引入以下模組(以 Maven 為例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-grpc-adapter</artifactId>
<version>x.y.z</version>
</dependency>
在使用 Sentinel gRPC Adapter 時,只需要將對應的 Interceptor 註冊至對應的客戶端或服務端中。其中客戶端的示例如下:
public class ServiceClient {
private final ManagedChannel channel;
ServiceClient(String host, int port) {
this.channel = ManagedChannelBuilder.forAddress(host, port)
.intercept(new SentinelGrpcClientInterceptor()) // 在此處註冊攔截器
.build();
// 在此處初始化客戶端 stub 類
}
}
服務端的示例如下:
import io.grpc.Server;
Server server = ServerBuilder.forPort(port)
.addService(new MyServiceImpl()) // 新增自己的服務實現
.intercept(new SentinelGrpcServerInterceptor()) // 在此處註冊攔截器
.build();
注意:由於 gRPC 攔截器中 ClientCall/ServerCall 以回撥的形式進行請求響應資訊的獲取,每次 gRPC 服務呼叫計算出的 RT 可能會不準確。Sentinel gRPC Adapter 目前只支援 unary call。
2.1.6 Reactive
注:從 1.5.0 版本開始支援,需要 Java 8 及以上版本。
Sentinel 提供 Reactor 的適配,可以方便地在 reactive 應用中接入 Sentinel。
使用時需引入以下模組(以 Maven 為例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-reactor-adapter</artifactId>
<version>x.y.z</version>
</dependency>
Sentinel Reactor Adapter 分別針對 Mono 和 Flux 實現了對應的 Sentinel Operator,從而在各種事件觸發時匯入 Sentinel 的相關邏輯。同時 Sentinel 在上層提供了 SentinelReactorTransformer 用於在組裝期裝入對應的 operator,使用者使用時只需要通過 transform 操作符來進行變換即可。
接入示例:
someService.doSomething() // return type: Mono<T> or Flux<T>
.transform(new SentinelReactorTransformer<>(resourceName)) // 在此處進行變換
.subscribe();
2.1.7 API Gateway
Sentinel 支援對 Spring Cloud Gateway、Zuul 等主流的 API Gateway 進行限流。
Spring Cloud Gateway
從 1.6.0 版本開始,Sentinel 提供了 Spring Cloud Gateway 的適配模組,可以提供兩種資源維度的限流:
route 維度:即在 Spring 配置檔案中配置的路由條目,資源名為對應的 routeId
自定義 API 維度:使用者可以利用 Sentinel 提供的 API 來自定義一些 API 分組
使用時需引入以下模組(以 Maven 為例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>x.y.z</version>
</dependency>
使用時只需注入對應的 SentinelGatewayFilter
例項以及 SentinelGatewayBlockExceptionHandler
例項即可。比如:
@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;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
因為Sentinel暫時只支援了Zuul1.x,具體用發這裡暫不介紹。
2.1.8 Apache RocketMQ
在 Apache RocketMQ 中,當消費者去消費訊息的時候,無論是通過 pull 的方式還是 push 的方式,都可能會出現大批量的訊息突刺。如果此時要處理所有訊息,很可能會導致系統負載過高,影響穩定性。但其實可能後面幾秒之內都沒有訊息投遞,若直接把多餘的訊息丟掉則沒有充分利用系統處理訊息的能力。我們希望可以把訊息突刺均攤到一段時間內,讓系統負載保持在訊息處理水位之下的同時儘可能地處理更多訊息,從而起到“削峰填谷”的效果:
上圖中紅色的部分代表超出訊息處理能力的部分。我們可以看到訊息突刺往往都是瞬時的、不規律的,其後一段時間系統往往都會有空閒資源。我們希望把紅色的那部分訊息平攤到後面空閒時去處理,這樣既可以保證系統負載處在一個穩定的水位,又可以儘可能地處理更多訊息。Sentinel 專門為這種場景提供了勻速器的特性,可以把突然到來的大量請求以勻速的形式均攤,以固定的間隔時間讓請求通過,以穩定的速度逐步處理這些請求,起到“削峰填谷”的效果,從而避免流量突刺造成系統負載過高。同時堆積的請求將會排隊,逐步進行處理;當請求排隊預計超過最大超時時長的時候則直接拒絕,而不是拒絕全部請求。
比如在 RocketMQ 的場景下配置了勻速模式下請求 QPS 為 5,則會每 200 ms 處理一條訊息,多餘的處理任務將排隊;同時設定了超時時間為 5 s,預計排隊時長超過 5 s 的處理任務將會直接被拒絕。示意圖如下圖所示:
RocketMQ 使用者可以根據不同的 group 和不同的 topic 分別設定限流規則,限流控制模式設定為勻速器模式(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER),比如:
private void initFlowControlRule() {
FlowRule rule = new FlowRule();
rule.setResource(KEY); // 對應的 key 為 `groupName:topicName`
rule.setCount(5);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
// 勻速器模式下,設定了 QPS 為 5,則請求每 200 ms 允許通過 1 個
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
// 如果更多的請求到達,這些請求會被置於虛擬的等待佇列中。等待佇列有一個 max timeout,如果請求預計的等待時間超過這個時間會直接被 block
// 在這裡,timeout 為 5s
rule.setMaxQueueingTimeMs(5 * 1000);
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
2.2 丟擲異常的方式定義資源
SphU
包含了 try-catch 風格的 API。用這種方式,當資源發生了限流之後會丟擲 BlockException。這個時候可以捕捉異常,進行限流之後的邏輯處理。示例程式碼如下:
// 1.5.0 版本開始可以利用 try-with-resources 特性
// 資源名可使用任意有業務語義的字串,比如方法名、介面名或其它可唯一標識的字串。
try (Entry entry = SphU.entry("resourceName")) {
// 被保護的業務邏輯
// do something here...
} catch (BlockException ex) {
// 資源訪問阻止,被限流或被降級
// 在此處進行相應的處理操作
}
特別地 ,若 entry 的時候傳入了熱點引數,那麼 exit 的時候也一定要帶上對應的引數(exit(count, args)),否則可能會有統計錯誤。這個時候不能使用 try-with-resources 的方式。另外通過 Tracer.trace(ex) 來統計異常資訊時,由於 try-with-resources 語法中 catch 呼叫順序的問題,會導致無法正確統計異常數,因此統計異常資訊時也不能在 try-with-resources 的 catch 塊中呼叫 Tracer.trace(ex)。
1.5.0 之前的版本的示例:
Entry entry = null;
// 務必保證finally會被執行
try {
// 資源名可使用任意有業務語義的字串
entry = SphU.entry("自定義資源名");
// 被保護的業務邏輯
// do something...
} catch (BlockException e1) {
// 資源訪問阻止,被限流或被降級
// 進行相應的處理操作
} finally {
if (entry != null) {
entry.exit();
}
}
注意 : SphU.entry(xxx) 需要與 entry.exit() 方法成對出現,匹配呼叫,否則會導致呼叫鏈記錄異常,丟擲 ErrorEntryFreeException 異常。
2.3 返回布林值方式定義資源
SphO
提供 if-else 風格的 API。用這種方式,當資源發生了限流之後會返回 false,這個時候可以根據返回值,進行限流之後的邏輯處理。示例程式碼如下:
// 資源名可使用任意有業務語義的字串
if (SphO.entry("自定義資源名")) {
// 務必保證finally會被執行
try {
/**
* 被保護的業務邏輯
*/
} finally {
SphO.exit();
}
} else {
// 資源訪問阻止,被限流或被降級
// 進行相應的處理操作
}
2.4 註解方式定義資源
Sentinel 支援通過 @SentinelResource 註解定義資源並配置 blockHandler 和 fallback 函式來進行限流之後的處理。示例:
// 原本的業務方法.
@SentinelResource(blockHandler = "blockHandlerForGetUser")
public User getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
// blockHandler 函式,原方法呼叫被限流/降級/系統保護的時候呼叫
public User blockHandlerForGetUser(String id, BlockException ex) {
return new User("admin");
}
注意 blockHandler 函式會在原方法被限流/降級/系統保護的時候呼叫,而 fallback 函式會針對所有型別的異常。請注意 blockHandler 和 fallback 函式的形式要求。
2.5 非同步呼叫支援
Sentinel 支援非同步呼叫鏈路的統計。在非同步呼叫中,需要通過 SphU.asyncEntry(xxx) 方法定義資源,並通常需要在非同步的回撥函式中呼叫 exit 方法。以下是一個簡單的示例:
try {
AsyncEntry entry = SphU.asyncEntry(resourceName);
// 非同步呼叫.
doAsync(userId, result -> {
try {
// 在此處處理非同步呼叫的結果.
} finally {
// 在回撥結束後 exit.
entry.exit();
}
});
} catch (BlockException ex) {
// Request blocked.
// Handle the exception (e.g. retry or fallback).
}
SphU.asyncEntry(xxx) 不會影響當前(呼叫執行緒)的 Context,因此以下兩個 entry 在呼叫鏈上是平級關係(處於同一層),而不是巢狀關係:
// 呼叫鏈類似於:
// -parent
// ---asyncResource
// ---syncResource
asyncEntry = SphU.asyncEntry(asyncResource);
entry = SphU.entry(normalResource);
若在非同步回撥中需要巢狀其它的資源呼叫(無論是 entry 還是 asyncEntry),只需要藉助 Sentinel 提供的上下文切換功能,在對應的地方通過 ContextUtil.runOnContext(context, f) 進行 Context 變換,將對應資源呼叫處的 Context 切換為生成的非同步 Context,即可維持正確的呼叫鏈路關係。示例如下:
public void handleResult(String result) {
Entry entry = null;
try {
entry = SphU.entry("handleResultForAsync");
// Handle your result here.
} catch (BlockException ex) {
// Blocked for the result handler.
} finally {
if (entry != null) {
entry.exit();
}
}
}
public void someAsync() {
try {
AsyncEntry entry = SphU.asyncEntry(resourceName);
// Asynchronous invocation.
doAsync(userId, result -> {
// 在非同步回撥中進行上下文變換,通過 AsyncEntry 的 getAsyncContext 方法獲取非同步 Context
ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
try {
// 此處巢狀正常的資源呼叫.
handleResult(result);
} finally {
entry.exit();
}
});
});
} catch (BlockException ex) {
// Request blocked.
// Handle the exception (e.g. retry or fallback).
}
}
3. 規則的種類
Sentinel 的所有規則都可以在記憶體態中動態地查詢及修改,修改之後立即生效。同時 Sentinel 也提供相關 API,供您來定製自己的規則策略。
Sentinel 支援以下幾種規則:流量控制規則 、熔斷降級規則 、系統保護規則 、來源訪問控制規則 和 熱點引數規則 。
3.1 流量控制規則 (FlowRule)
流量規則的定義
重要屬性:
Field | 說明 | 預設值 |
---|---|---|
resource | 資源名,資源名是限流規則的作用物件 | |
count | 限流閾值 | |
grade | 限流閾值型別,QPS 或執行緒數模式 | QPS 模式 |
limitApp | 流控針對的呼叫來源 | default,代表不區分呼叫來源 |
strategy | 判斷的根據是資源自身,還是根據其它關聯資源 (refResource),還是根據鏈路入口 | 根據資源本身 |
controlBehavior | 流控效果(直接拒絕 / 排隊等待 / 慢啟動模式) | 直接拒絕 |
同一個資源可以同時有多個限流規則。
通過程式碼定義流量控制規則
理解上面規則的定義之後,我們可以通過呼叫 FlowRuleManager.loadRules() 方法來用硬編碼的方式定義流量控制規則,比如:
private void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule(resourceName);
// set limit qps to 20
rule.setCount(20);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
3.2 熔斷降級規則 (DegradeRule)
熔斷降級規則包含下面幾個重要的屬性:
Field | 說明 | 預設值 |
---|---|---|
resource | 資源名,即限流規則的作用物件 | |
count | 閾值 | |
grade | 降級模式,根據 RT 降級還是根據異常比例降級 | |
timeWindow | 降級的時間,單位為 s |
同一個資源可以同時有多個降級規則。
理解上面規則的定義之後,我們可以通過呼叫 DegradeRuleManager.loadRules() 方法來用硬編碼的方式定義流量控制規則。
private void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
rule.setResource(KEY);
// set threshold RT, 10 ms
rule.setCount(10);
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
rule.setTimeWindow(10);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
3.3 系統保護規則 (SystemRule)
規則包含下面幾個重要的屬性:
Field | 說明 | 預設值 |
---|---|---|
highestSystemLoad | 最大的 load1,參考值 | -1 (不生效) |
avgRt | 所有入口流量的平均響應時間 | -1 (不生效) |
maxThread | 入口流量的最大併發數 | -1 (不生效) |
qps | 所有入口資源的 QPS | -1 (不生效) |
理解上面規則的定義之後,我們可以通過呼叫 SystemRuleManager.loadRules() 方法來用硬編碼的方式定義流量控制規則。
private void initSystemRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(10);
rules.add(rule);
SystemRuleManager.loadRules(rules);
}
3.4 訪問控制規則 (AuthorityRule)
很多時候,我們需要根據呼叫方來限制資源是否通過,這時候可以使用 Sentinel 的訪問控制(黑白名單)的功能。黑白名單根據資源的請求來源(origin)限制資源是否通過,若配置白名單則只有請求來源位於白名單內時才可通過;若配置黑名單則請求來源位於黑名單時不通過,其餘的請求通過。
授權規則,即黑白名單規則(AuthorityRule)非常簡單,主要有以下配置項:
resource:資源名,即限流規則的作用物件
limitApp:對應的黑名單/白名單,不同 origin 用 , 分隔,如 appA,appB
strategy:限制模式,AUTHORITY_WHITE 為白名單模式,AUTHORITY_BLACK 為黑名單模式,預設為白名單模式
這一篇先初步的介紹什麼是資源,什麼是規則,並且介紹了Sentinel對常見主流框架的適配,下一篇,我們詳細來聊聊幾種服務限流的方式。
參考:
https://github.com/alibaba/Sentinel