Current limiting and fusing of spring cloud services

1, Current limiting

1. Meaning

The purpose of current limiting is to protect the system by limiting the speed of concurrent access / requests or requests within a time window. Once the limit rate is reached, it can be denied service, that is, directed to the error page or friendly display page, queued or waiting.

Flow restriction can ensure the availability of our API services to all users and prevent network attacks. In high concurrency applications, current limiting is an inseparable topic.

2. How to realize current limiting

① Token bucket algorithm

The principle of token bucket algorithm is that the system will put tokens into the bucket at a constant speed. If the request needs to be processed, you need to obtain a token from the bucket first. When there is no token in the bucket, the service will be rejected.

QPS:

Requests per second, that is, how many requests the server processed in one second.

② Improve bandwidth

Prices of different alicloud hosts:

 

Implementation of Gateway current limiting

① modify version number and import dependency

  <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
        <spring-cloud-alibaba.version>2.1.1.RELEASE</spring-cloud-alibaba.version> 

Spring Cloud Gateway officially provides the RequestRateLimiterGatewayFilterFactory flow controller class, which uses redis and lua scripts to implement token bucket.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

② . open redis and add redis configuration

The Gateway realizes current limiting through the built-in RequestRateLimiter filter, uses the token bucket algorithm and saves intermediate data with the help of Redis. You can set the current limiting dimension by customizing KeyResolver.
I. limit the flow of the requested target URL
II. Limit the current of source IP
III. current limiting for specific users

Add redis configuration

redis:

         host: 127.0.0.1

         port: 6379

          # password: root123

         database: 0

If the redis connection fails, the current limiting function cannot be enabled. Because redis is not used as a container to save tokens, the current limiting function will naturally fail.

redis configuration information can be saved to nacos and read by adding a client of the nacos configuration center

③ . request current limiting configuration RequestRateLimiterConfig

package com.yk.code;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import reactor.core.publisher.Mono;

/**
 * Request current limiting configuration
 */
@SuppressWarnings("all")
@Configuration
public class RequestRateLimiterConfig {

    /**
     * Current limiting by IP
     */
    @Bean
    @Primary
    public KeyResolver ipAddrKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }

    /**
     * Current limit by user
     */
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }

    /**
     * Limit the flow by URL, that is, count the number of requests per second by URL grouping. All URL requests exceeding the flow limit will return to 429 status
     *
     * @return
     */
    @Bean
    KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().toString());
    }

}

 

④ Add current limiting configuration

Cancel the conmponent annotation in the dynamicreutingconfig file, that is, cancel the previous custom configuration

filters:
 - name: RequestRateLimiter
  args:
    #Parser for current limiting keys Bean Object name,use SpEL Expression basis#{@ beanName} get Bean pair
 as
   key-resolver: '#{@ipAddrKeyResolver}'
    #Token bucket fill rate, how many requests per second the user is allowed to process
   redis-rate-limiter.replenishRate: 10
    #Total capacity of token bucket, the maximum number of requests allowed to be completed in one second
   redis-rate-limiter.burstCapacity: 20

pom file:

 

server:
  #The 8084 port number here is just like the 8080 of the previous external tomcat. Let's access it through the browser
  #However, this service only makes a route, which will route the request to other micro services (generally consumers) for processing
  port: 8084
 
spring:
  application:
    #Microservice name
    name: gateway
  redis:
   host: 47.100.191.44
   port: 6379
   password: xiaoli_redis
   database: 0
  cloud:
    nacos:
      discovery:
        #Specify the address of the nacos registry
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
#          Previously: localhost:8082/user/aa
#          Route: localhost:8084/consumer/user/aa
#          Route: localhost:8084/provider/user/aa
          #Whether it is combined with the service discovery component and forwarded to the specific service instance through the service ID (which must be set to uppercase). Default false
          #true means that the routing rule based on service discovery is enabled.
          enabled: false
          #When accessing after configuration, the service ID does not need to be capitalized
          lower-case-service-id: true
      routes:  #route
        # Route id (id: id, unique)
        - id: user-consumer-api
          #The target service address (uri: address, address after request forwarding) will automatically obtain the service IP from the registry without manual writing
          uri: lb://consumer
          #Priority, the smaller the priority
          #order: 999
          #Routing conditions (predicates: assertions)
          predicates:
            # Path matching,
#             localhost:8082/user/aa cannot enter
#            localhost:8082/cum/user/aa
            - Path=/cum/**
          filters:  #filter
            #Example of path prefix deletion: request / name/bar/foo,StripPrefix=2. After removing the first two prefixes, the path forwarded to the target service is / foo
            #Prefix filtering, request address: http://localhost:8084/usr/hello
            #Remove one path prefix from the configuration here, and then configure the above Path=/usr / * *, and * * will be forwarded to the specified micro service
            #Because this api is equivalent to the service name, it is only added to facilitate the code of nginx in the future. For the service client of the service provider, this address is not required, so it needs to be removed
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                #Parser for current limiting keys Bean Object name,use SpEL Expression basis#{@ beanName} get Bean object
                key-resolver: '#{@ipAddrKeyResolver}'
                #Token bucket fill rate, how many requests per second the user is allowed to process
                redis-rate-limiter.replenishRate: 10
                #Total capacity of token bucket, the maximum number of requests allowed to be completed in one second
                redis-rate-limiter.burstCapacity: 20
#            - name: Hystrix
#              args:
#                name: fallback
#                fallbackUri: forward:/fallback
        #producer
        # Route id (id: id, unique)
        - id: user-provider-api
          #The target service address (uri: address, address after request forwarding) will automatically obtain the service IP from the registry without manual writing
          uri: lb://provider
          #Priority, the smaller the priority
          #order: 999
          #Routing conditions (predicates: assertions)
          predicates:
            # Path matching,
            - Path=/api/prv/**
          filters:
            #Example of path prefix deletion: request / name/bar/foo,StripPrefix=2. After removing the first two prefixes, the path forwarded to the target service is / foo
            #Prefix filtering, request address: http://localhost:8084/usr/hello
            #Remove one path prefix from the configuration here, and then configure the above Path=/usr / * *, and * * will be forwarded to the specified micro service
            #Because this api is equivalent to the service name, it is only added to facilitate the code of nginx in the future. For the service client of the service provider, this address is not required, so it needs to be removed
            - StripPrefix=2
            - name: Hystrix
              args:
                name: fallback
                fallbackUri: forward:/fallback
logging:
  level:
    #The log level of spring cloud gateway is debug, which is convenient for debugging
    org.springframework.cloud.gateway: trace
    org.springframework.http.server.reactive: debug
    org.springframework.web.reactive: debug
    reactor.ipc.netty: debug
#springboot monitors the actor and exposes all endpoints
management:
  endpoints:
    web:
      exposure:
        include: '*'
#Custom configuration
gateway:
  nacos:
#    #Configuration center address
    server-addr: ${spring.cloud.nacos.discovery.server-addr}
#    #Specified environment
    # namespace: xxx-xx-xx-xx
#    #Read Data Id in configuration management
    data-id: dynamic-routing.json
    group: DEFAULT_GROUP

Connect the service:

⑤. Conduct pressure test

Unzip this file:

Double click this to run:

 

Convert this software into Chinese mode:

Increase pressure:

 

 

Add request:

 

 

View request results:

 

Start:

 

Increase the number of threads to 20 and start the result:

Failed when the number of threads is changed to 30:

 

II. Fusing

Difference between service degradation and service fusing

1. Meaning

In the distributed system, the gateway is used as the entrance of traffic. A large number of requests enter the gateway and initiate calls to the back-end remote system or service. The back-end service will inevitably produce call failure (timeout or exception). In case of failure, the requests cannot accumulate on the gateway. It needs to fail quickly and return back, which requires fusing and degradation on the gateway.

2. Realize fusing

① . import dependency

<dependency> 

 <groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>

</dependency>

② . configuration

 

③. Test

package com.yk.code.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Xiaobao's Treasure
 */
@RestController
public class testController {

    @RequestMapping("/fallback")
    public Object fallback(){
        Map<String,Object> map=new HashMap<>();
        map.put("code",204);
        map.put("msg","The service has been degraded");
        return map;
    }
}

 

Start:

It's normal now

We simulate an error, stop the operation of the producer, and then access the path:

 

End of this period ~~~~

 

Keywords: Java Spring Cloud Microservices

Added by grim1208 on Mon, 21 Feb 2022 12:24:35 +0200