28 Eylül 2021 Salı

SpringCloud Gateway RequestRateLimiter Sınıfı - API Rate Limiter İçin Kullanılır

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
Maven
Şöyle yaparız. RequestRateLimiter altta Redis kullanır. Dolayısıyla data-redis gerekir.
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifatId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
Açıklaması şöyle
RequestRateLimiter is one of the many gateway filters offered by SCG. The implementation determines whether a request is allowed to proceed or has exceeded its limit. ...
the gateway comes with one that uses a user’s Principal name. A secured gateway is needed to resolve a user’s principal name, but you have the option to implement the KeyResolver interface to instead resolve a different key from the ServerWebExchange
You can point to a custom KeyResolver bean (for example, named customKeyResolver) in the configuration by using a SPEL #{@customKeyResolver} expression. 
RequestRateLimiter sınfı RequestRateLimiterGatewayFilterFactory tarafından yaratılır

Açıklaması şöyle
The provided Redis implementation lets you define the request rate at which users can make calls within a certain time period. It also makes it possible to accommodate sporadic demands while constrained by the defined consumption rate. For example, a configuration can define a replenish rate of 500 requests per second by setting the redis-rate-limiter.replenishRate=500 property and a burst capacity of 1000 request per second by setting the redis-rate-limiter.burstCapacity=1000 property. Doing so limits consumption to 500 requests every second. If a burst in the number of requests occurs, only 1,000 requests are allowed. However, because 1,000 requests are a quota of 2 seconds, the gateway would not route requests for the next second. The configuration also lets you define how many tokens a request would cost by setting the property redis-rate-limiter.requestedTokens property. Typically, it is set to 1.

To use a gateway with a request limiting feature, it needs to be configured with the RequestRateLimiter gateway filter. 
Yani şöyle yaparız
spring:
cloud: gateway: routes: - id: route1 uri: http://localhost:8081 predicates: - Path=/backend filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 500 redis-rate-limiter.burstCapacity: 1000 redis-rate-limiter.requestedTokens: 1
Açıklaması şöyle
burstCapacity, the total capacity of the token bucket.
replenishRate, the average rate at which the token bucket is filled per second.

KeyResolver  Arayüzü
Şu satırı dahil ederiz
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
Eğer KeyResolver kullanmak istersek şöyle yaparız
spring:
cloud: gateway: routes: - id: route1 uri: http://localhost:8081 predicates: - Path=/backend filters: - name: RequestRateLimiter args: rate-limiter: "#{customRateLimiter}" key-resolver: "#{customKeyResolver}" @Bean public KeyResolver customKeyResolver { return exchange -> .... // returns a Mono of String }
Çok detaylı bir örnek burada
Örnek
Şöyle yaparız
server:
  port: 8081
spring:
  cloud:
    gateway:
      routes:
      - id: limit_route
        uri: http://httpbin.org:80/get
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
        filters:
        - name: RequestRateLimiter
          args:
            key-resolver: '#{@hostAddrKeyResolver}'
            redis-rate-limiter.replenishRate: 1
            redis-rate-limiter.burstCapacity: 3
  application:
    name: gateway-limiter
  redis:
    host: localhost
    port: 6379
    database: 0
Açıklaması şöyle
key-resolver, the name of the bean object of the resolver for the throttled key. It uses SpEL expressions to get bean objects from the Spring container based on #{@beanName}.
Hostname özelliğine göre sınırlamak için şöyle yaparız
public class HostAddrKeyResolver implements KeyResolver {

  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    return Mono.just(exchange.getRequest().getRemoteAddress()
      .getAddress().getHostAddress());
  }

}

@Bean
public HostAddrKeyResolver hostAddrKeyResolver() {
  return new HostAddrKeyResolver();
}
URI'ye göre sınırlamak için şöyle yaparız
public class UriKeyResolver  implements KeyResolver {

  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    return Mono.just(exchange.getRequest().getURI().getPath());
  }
}

@Bean
public UriKeyResolver uriKeyResolver() {
  return new UriKeyResolver();
}
Örnek
Şöyle yaparız
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.web.server.ServerWebExchange;

import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.netty.util.internal.StringUtil;
import reactor.core.publisher.Mono;

public class CustomerKeyResolver implements KeyResolver {

  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    String apiName = exchange.getRequest().getPath().toString();

    List<String> customerIds = exchange.getRequest().getHeaders().get("X-Customer-Id");
    if (customerIds != null && ...) {
      return Mono.just(customerIds.get(0) + StringUtil.COMMA + apiName);
    }

    List<String> authHeaders = exchange.getRequest().getHeaders().get("Authorization");
    if (authHeaders != null && ...) {
      ...
    }

    return Mono.just(StringUtil.EMPTY_STRING);
  }
}

Hiç yorum yok:

Yorum Gönder