The background,
In our usual development process, A request generally needs to pass through multiple microservices, ** for example: ** requests flow from A service to B service, if A service request is too fast, resulting in slow response of B service, then it will inevitably lead to system problems. Because we need finite flow operations.
Two, to achieve the function
- Provides custom flow limiting key generation, needs to be implemented
KeyResolver
Interface. - Provides the default traffic limiting algorithm, implementation
RateLimiter
Interface. - When the key of the flow limiting is empty, the traffic is directly not restricted, and is released by the parameter
spring.cloud.gateway.routes[x].filters[x].args[x].deny-empty-key
To control the - The corresponding code returned to the client during traffic limiting is
spring.cloud.gateway.routes[x].filters[x].args[x].status-code
To control, you need to write thisorg.springframework.http.HttpStatus
Class enumeration value. RequestRateLimiter
Can only usename || args
This configuration mode cannot be configured in shorthand mode.
RequestRateLimiter
The filterredis-rate-limiter
Parameter is inRedisRateLimiter
theCONFIGURATION_PROPERTY_NAME
Property configured. Constructor method.
Traffic limiting at the gateway layer
The key generation rule for traffic limiting is PrincipalNameKeyResolver and RedisRateLimiter, which is the token bucket algorithm by default.
1. Use the default redis to limit traffic
The RequestRateLimiter filter is provided by default in the Spring Cloud Gateway for traffic limiting.
1. Introduce jar packages
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
Copy the code
2. Write a configuration file
spring:
application:
name: gateway-9205
cloud:
nacos:
discovery:
server-addr: localhost:8847
gateway:
routes:
- id: user-provider-9206
uri: lb://user-provider-9206
predicates:
- Path=/user/**
filters:
- RewritePath=/user(?
/? . *),
$\{segment}
- name: RequestRateLimiter
args:
If the key returned is empty, no limiting is performed
deny-empty-key: false
# How many tokens are generated per second
redis-rate-limiter.replenishRate: 1
# The maximum token in 1 second, that is, the burst flow that can be allowed in 1s, is set to 0 to block all requests
redis-rate-limiter.burstCapacity: 1
Request several tokens per request
redis-rate-limiter.requestedTokens: 1
redis:
host: 192.1687.1.
database: 12
port: 6379
password: 123456
server:
port: 9205
debug: true
Copy the code
3. The gateway responds normally
4. Gateway traffic limiting response
2. Customize the traffic limiting algorithm and key
1. Customize traffic limiting keys
Write a class that implements the KeyResolver interface.
package com.huan.study.gateway;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Optional;
/** * The key for limiting traffic gets **@authorHuan. Fu 2021 1/9/7-10:25 am */
@Slf4j
@Component
public class DefaultGatewayKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
// Get the current route
Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
ServerHttpRequest request = exchange.getRequest();
String uri = request.getURI().getPath();
log.info("Currently returned URI :[{}]", uri);
return Mono.just(Optional.ofNullable(route).map(Route::getId).orElse("") + "/"+ uri); }}Copy the code
Writing in the configuration file (part)
spring:
cloud:
gateway:
routes:
- id: user-provider-9206
filters:
- name: RequestRateLimiter
args:
# return the key that limits the flow
key-resolver: "#{@defaultGatewayKeyResolver}"
Copy the code
2. Custom traffic limiting algorithm
Write a class to implement RateLimiter, where memory limiting is used
package com.huan.study.gateway;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.ratelimit.AbstractRateLimiter;
import org.springframework.cloud.gateway.support.ConfigurationService;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
/ * * *@authorHuan. Fu 2021 1/9/7-10:36 am */
@Component
@Slf4j
@Primary
public class DefaultGatewayRateLimiter extends AbstractRateLimiter<DefaultGatewayRateLimiter.Config> {
/** * corresponds to the configuration properties in the configuration file */
private static final String CONFIGURATION_PROPERTY_NAME = "default-gateway-rate-limiter";
private RateLimiter rateLimiter = RateLimiter.create(1);
protected DefaultGatewayRateLimiter(ConfigurationService configurationService) {
super(DefaultGatewayRateLimiter.Config.class, CONFIGURATION_PROPERTY_NAME, configurationService);
}
@Override
public Mono<Response> isAllowed(String routeId, String id) {
log.info("Default gateway routeId:[{}], ID :[{}]", routeId, id);
Config config = getConfig().get(routeId);
return Mono.fromSupplier(() -> {
boolean acquire = rateLimiter.tryAcquire(config.requestedTokens);
if (acquire) {
return new Response(true, Maps.newHashMap());
} else {
return new Response(false, Maps.newHashMap()); }}); }@Getter
@Setter
@ToString
public static class Config {
/** * How many tokens are requested each time */
privateInteger requestedTokens; }}Copy the code
Writing in the configuration file (part)
spring:
cloud:
gateway:
routes:
- id: user-provider-9206
filters:
- name: RequestRateLimiter
args:
# Customize traffic limiting rules
rate-limiter: "#{@defaultGatewayRateLimiter}"
Copy the code
Note ⚠️ : this class requires the @primary annotation.
3. Write in the configuration file
spring:
application:
name: gateway-9205
cloud:
nacos:
discovery:
server-addr: localhost:8847
gateway:
routes:
- id: user-provider-9206
uri: lb://user-provider-9206
predicates:
- Path=/user/**
filters:
- RewritePath=/user(?
/? . *),
$\{segment}
- name: RequestRateLimiter
args:
# Customize traffic limiting rules
rate-limiter: "#{@defaultGatewayRateLimiter}"
# return the key that limits the flow
key-resolver: "#{@defaultGatewayKeyResolver}"
If the key returned is empty, no limiting is performed
deny-empty-key: false
Response code 429: too many requests
status-code: TOO_MANY_REQUESTS
# each request to apply for a few token default gateway - rate - value is defined in defaultGatewayRateLimiter limiter.
default-gateway-rate-limiter.requestedTokens: 1
server:
port: 9205
debug: true
Copy the code
Finish the code
Gitee.com/huan1993/sp…
5. Reference documents
1, the docs. Spring. IO/spring – clou…