Sentinel is a flow control component of Alibaba open source oriented to distributed service architecture. It mainly takes flow as the entry point and guarantees the stability of micro-service from multiple dimensions such as flow control, fuse downgrading and system adaptive protection.
In addition to the Spring Cloud Gateway official RequestRateLimiterGatewayFilterFactory filter factory to implement the Gateway current limit, we can also choose to integrate Sentinel to realize current limit.
In this article, we will learn the basic knowledge of Sentinel integrated with Spring Cloud Gateway. You can refer to Sentinel official Documentation (SentinelGuard.io).
Without further ado, let’s begin today’s lesson.
Sentinel current-limiting
Beginning with version 1.6.0, Sentinel provides adaptive modules for Spring Cloud Gateway, which can provide flow limiting for two resource dimensions:
- Route dimension: the route entry configured in the Spring configuration file with the corresponding routeId resource name
- Custom API dimensions: Users can customize some API groups using the API provided by Sentinel
1. Add dependencies
<! -- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<! -- SpringCloud Alibaba Sentinel Gateway -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
Copy the code
2. Custom flow limiting exception processing class
/** * Custom traffic limiting exception handling **@author ezhang
*/
public class SentinelFallbackHandler implements WebExceptionHandler {
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
ServerHttpResponse serverHttpResponse = exchange.getResponse();
serverHttpResponse.getHeaders().add("Content-Type"."application/json; charset=UTF-8");
byte[] datas = "{"code":429, "msg":"The request exceeded the maximum number, please try again later"}".getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
return serverHttpResponse.writeWith(Mono.just(buffer));
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
}
if(! BlockException.isBlockException(ex)) {return Mono.error(ex);
}
return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
}
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
returnGatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable); }}Copy the code
This class implements the exception handling interface WebExceptionHandler in Spring WebFlux.
This class in addition to the custom, also can be used directly Sentinel own SentinelGatewayBlockExceptionHandler class.
public class SentinelGatewayBlockExceptionHandler implements WebExceptionHandler {
private List<ViewResolver> viewResolvers;
privateList<HttpMessageWriter<? >> messageWriters;private final Supplier<Context> contextSupplier = () -> {
return new Context() {
publicList<HttpMessageWriter<? >> messageWriters() {return SentinelGatewayBlockExceptionHandler.this.messageWriters;
}
public List<ViewResolver> viewResolvers(a) {
return SentinelGatewayBlockExceptionHandler.this.viewResolvers; }}; };public SentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolvers;
this.messageWriters = serverCodecConfigurer.getWriters();
}
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
return response.writeTo(exchange, (Context)this.contextSupplier.get());
}
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
} else {
return! BlockException.isBlockException(ex) ? Mono.error(ex) :this.handleBlockedRequest(exchange, ex).flatMap((response) -> {
return this.writeResponse(response, exchange); }); }}private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
returnGatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable); }}Copy the code
SentinelGatewayBlockExceptionHandler class is also realized WebExceptionHandler interface.
3. Traffic limiting rule configuration class
/** * Traffic limiting rule configuration class **@author ezhang
*/
@Configuration
public class GatewayConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelFallbackHandler sentinelGatewayExceptionHandler(a) {
return new SentinelFallbackHandler();
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter(a) {
return new SentinelGatewayFilter();
}
@PostConstruct
public void doInit(a) {
// Load the gateway traffic limiting rule
initGatewayRules();
}
/** * Gateway traffic limiting rule */
private void initGatewayRules(a) {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("cloud-gateway")
.setCount(3) // Traffic limiting threshold
.setIntervalSec(60)); // Statistics time window, in seconds, default is 1 second
// Load the gateway traffic limiting ruleGatewayRuleManager.loadRules(rules); }}Copy the code
4. Application. Yml configuration
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-gateway
uri: http://192.168.1.211:8088
predicates:
- Path=/ytb/**
filters:
- StripPrefix=1
Copy the code
5. Start the test
Start the project after we visit this interface at http://localhost:8080/ytb/file/getFileList
At this point, the return is normal, but when we access the fourth time within a minute, an exception will be returned, indicating that the traffic limiting is successful.
We can also run this command from CMD to view real-time statistics
curl http://localhost:8719/cnode? id=cloud-gateway
The output content is in the following format:
Among them:
- Thread: indicates the number of threads currently processing the resource.
- Pass: requests that arrive within one second;
- Blocked: represents the number of requests controlled by traffic in a second;
- Success: represents the request that was successfully processed within one second;
- Total: indicates the total number of incoming requests and blocked requests within one second.
- RT: indicates the average response time of the resource in one second.
- 1m-pass: requests that arrive within a minute;
- 1m-block: the request is blocked within one minute.
- 1m-all: indicates the sum of incoming requests and blocked requests within one minute.
- Exception: indicates the total number of service exceptions in one second.
In addition, whether they trigger limiting, fusing downscaling or system protection, their second level intercept details are logged in ${user_HOME}/logs/ CSP/sentinel-block-.log. If no interception occurs, the log does not appear. The log format is as follows:
The 2021-12-24 15:46:02 | 1 | cloud - gateway, ParamFlowException, $D, | 2, 0, 2021-12-24 15:46:03 | 1 | cloud - gateway, ParamFlowException, $D | 1, 0Copy the code
Description:
index | example | instructions |
---|---|---|
1 | The 2021-12-24 15:46:03 |
The time stamp |
2 | 1 |
The first resource that occurs in this second |
3 | cloud-gateway |
The name of the resource |
4 | XXXException |
The reason for interception, usuallyFlowException Is blocked by traffic limiting rules,DegradeException Means demoted,SystemBlockException It is intercepted by the system protection |
5 | 2, 0 |
2 number of intercepts, 0 is meaningless and negligible |
Sentinel packet current limiting
Configure traffic limiting for cloud-system and Cloud-YTB groups
1.application.yml
The configuration file
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-ytb
uri: http://192.168.1.211:8088
predicates:
- Path=/ytb/**
filters:
- StripPrefix=1
- id: cloud-system
uri: http://192.168.1.211:8088
predicates:
- Path=/system/**
filters:
- StripPrefix=1
Copy the code
2. Traffic limiting rule configuration class
/** * Traffic limiting rule configuration class **@author ezhang
*/
@Configuration
public class GatewayConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelFallbackHandler sentinelGatewayExceptionHandler(a) {
return new SentinelFallbackHandler();
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter(a) {
return new SentinelGatewayFilter();
}
@PostConstruct
public void doInit(a) {
/ / group
initCustomizedApis();
// Load the gateway traffic limiting rule
initGatewayRules();
}
/** * Gateway traffic limiting rule */
private void initGatewayRules(a) {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("system-api")
.setCount(3) // Traffic limiting threshold
.setIntervalSec(60)); // Statistics time window, in seconds, default is 1 second
rules.add(new GatewayFlowRule("ytb-api")
.setCount(6) // Traffic limiting threshold
.setIntervalSec(60));
// Load the gateway traffic limiting rule
GatewayRuleManager.loadRules(rules);
}
private void initCustomizedApis(a) {
Set<ApiDefinition> definitions = new HashSet<>();
/ / cloud - system group
ApiDefinition api1 = new ApiDefinition("system-api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {
{
// Matches /file with all requests for its subpath
add(new ApiPathPredicateItem().setPattern("/system/file/**") .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX)); }});/ / cloud - ytb group
ApiDefinition api2 = new ApiDefinition("ytb-api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {
{
// Matches only /file/getFileList
add(new ApiPathPredicateItem().setPattern("/ytb/file/getFileList")); }}); definitions.add(api1); definitions.add(api2); GatewayApiDefinitionManager.loadApiDefinitions(definitions); }}Copy the code
Visit: http://localhost:8080/system/file/getFileList (trigger current limiting access: http://localhost:8080/system/user/list (not trigger current limiting access: http://localhost:8080/ytb/file/getFileList (trigger current limiting access: http://localhost:8080/ytb/file/updateFileInfo (not trigger current limit)
Sentinel Custom exception
Sentinel supports custom exception handling.
Solution 1: YML configuration
# Spring
spring:
cloud:
sentinel:
scg:
fallback:
mode: response
response-body: '{"code":403," MSG ":" request exceeded the maximum number, please try again later "}'
Copy the code
After starting the test to trigger flow limiting:
Solution 2: The custom SentinelFallbackHandler is injected into GatewayConfig
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelFallbackHandler sentinelGatewayExceptionHandler(a) {
return new SentinelFallbackHandler();
}
Copy the code
Custom exception can make the trigger current limit returns information more neat, if we directly use the Sentinel’s own SentinelGatewayBlockExceptionHandler class after injection into the GatewayConfig then trigger current limit returns such exception information
Here’s a quick look at how the Spring Cloud Gateway integration Sentinel is configured to implement traffic limiting. There is no in-depth and systematic study of Sentinel. In the future, we will learn about Sentinel fuse downgrading.
Now that the Spring Cloud Gateway series is over, I’m ready to start Nacos.