Welcome to my GitHub
https://github.com/zq2599/blog_demos
Content: classification and summary of all original articles and supporting source code, involving Java, Docker, Kubernetes, DevOPS, etc;
Overview of this article
-
This article is the eighth in the Spring Cloud Gateway series. After the previous study, we have almost understood the filter. Today, let's complete the last section of the filter: RequestRateLimiter
-
The default current limiter is implemented based on redis, and the current limiting algorithm is a familiar token bucket( Token Bucket Algorithm ), the principle of token poke is not discussed here. You should understand it by looking at the following figure: the bucket capacity of tokens is limited, for example, up to 20, and the speed of tokens entering the bucket is constant (note that this is the difference from the leaky bucket algorithm), for example, 10 tokens per second, and each request at the bottom will be processed only if it can get a token:
RequestRateLimiter basic routine
- The steps to use the RequestRateLimiter filter are very simple:
- Prepare available redis
- Add dependency org.springframework.boot: spring boot starter data redis reactive in maven or gradle
- Determine what dimension to limit the flow according to, for example, the username parameter in the request. This is accomplished by writing the implementation of the KeyResolver interface
- Configure the application.yml file and add a filter
- The above is the routine of using RequestRateLimiter filter. Is it simple? Next, let's code first and then verify
Source download
- The complete source code in this actual combat can be downloaded from GitHub. The address and link information are shown in the table below( https://github.com/zq2599/blog_demos):
name | link | remarks |
---|---|---|
Project Home | https://github.com/zq2599/blog_demos | The project is on the GitHub home page |
git warehouse address (https) | https://github.com/zq2599/blog_demos.git | The warehouse address of the source code of the project, https protocol |
git warehouse address (ssh) | git@github.com:zq2599/blog_demos.git | The project source code warehouse address, ssh protocol |
- There are multiple folders in this git project. The source code of this article is in the spring cloud tutorials folder, as shown in the red box below:
- There are several sub projects under the spring cloud tutorials folder. The code of this chapter is gateway requester, as shown in the red box below:
preparation
- In order to better demonstrate the effect of Gateway, a new web interface is added in the code of service provider provider hello (Hello.java), which can accept an input parameter:
@GetMapping("/userinfo") public String userInfo(@RequestParam("username") String username) { return Constants.HELLO_PREFIX + " " + username + ", " + dateStr(); }
- We will use the above interface for later tests;
code
- Under the parent project spring cloud tutorials, add a new sub project gateway requeststratelimiter. Its pom.xml content is as follows, focusing on org.springframework.boot: spring boot starter data redis reactive:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-cloud-tutorials</artifactId> <groupId>com.bolingcavalry</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>gateway-requestratelimiter</artifactId> <dependencies> <dependency> <groupId>com.bolingcavalry</groupId> <artifactId>common</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> </dependencies> </project>
- For the configuration file application.yml, please note that several parameters of requestratelimit have been added with detailed comments in Chinese:
server: #Service port port: 8081 spring: application: name: circuitbreaker-gateway # redis configuration redis: host: 192.168.50.43 port: 6379 cloud: gateway: routes: - id: path_route uri: http://127.0.0.1:8082 predicates: - Path=/hello/** filters: - name: RequestRateLimiter args: # The speed of token entering the bucket is 100 per second, which is equivalent to QPS redis-rate-limiter.replenishRate: 100 # The bucket can hold 200 tokens, which is equivalent to the peak value. Note that 200 tokens can be removed from the bucket in the first second, but only 100 tokens can be obtained in the second second second, because the speed of entering the bucket is 100 tokens per second redis-rate-limiter.burstCapacity: 200 # Number of tokens required per request redis-rate-limiter.requestedTokens: 1
- The code that specifies the current limiting dimension is CustomizeConfig.java. Here, the current is limited according to the value of the request parameter username. It is assumed that half of the requested username in the real request is equal to Tom and the other half is equal to Jerry. According to the configuration of application.yml, Tom's request QPS is 10 and Jerry's QPS is also 10:
package com.bolingcavalry.gateway.config; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; import java.util.Objects; @Configuration public class CustomizeConfig { @Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username")); } }
- Startup class RequestRateLimiterApplication.java without nutrition:
package com.bolingcavalry.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class RequestRateLimiterApplication { public static void main(String[] args) { SpringApplication.run(RequestRateLimiterApplication.class,args); } }
- After the code is written, start verification;
Verification (barrel capacity equals barrel feeding speed)
-
First, verify the effect when the bucket capacity is equal to the bucket speed. Please modify the file in application.yml of gateway requester application so that the values of redis-rate-limiter.replenishRate and redis-rate-limiter.burstCapacity are equal to 100, that is, the bucket size is equal to 100 and the number of tokens put in per second is also 100
-
Ensure that redis is started and consistent with the configuration in application.yml
-
Start nacos (provider Hello dependency)
-
Start service provider provider hello
-
Start the gateway requestrequest delimiter
-
In order to simulate the web request, I use Apache Benchmark, the download address of windows version:
https://www.apachelounge.com/download/VS16/binaries/httpd-2.4.48-win64-VS16.zip -
After downloading and decompressing the above files, you can use them. After entering Apache24\bin on the console, execute the following command, which means sending 10000 requests to the specified address, and the number of concurrent requests is 2:
ab -n 10000 -c 2 http://localhost:8081/hello/userinfo?username=Tom
- The console output is as follows. It can be seen that in less than eight seconds, only 800 are successful, which proves that the current limit meets the expectation:
Verification (barrel capacity is greater than barrel feeding speed)
-
Next, try the current limiting effect when the barrel capacity is greater than the barrel inlet speed, which has a very important reference value for us to control the peak response
-
Please modify the file in the application.yml of the gateway requeststratelimiter application. redis-rate-limiter.replenishRate remains unchanged at 100, but redis-rate-limiter.burstCapacity is changed to 200, that is, the number of tokens put in per second is still 100, but the capacity of the bucket has doubled
-
Restart the application gateway requestdelimiter
-
Execute the following command again, which means that 10000 requests are sent to the specified address, and the number of concurrent requests is 2:
ab -n 10000 -c 2 http://localhost:8081/hello/userinfo?username=Tom
- The test results are shown in the figure below. It can be seen that it meets the expectations. All tokens in the bucket can be used up to support the scenario where the peak exceeds QPS:
Validation (limit flow according to username's dimension)
-
Next, verify whether the current limiting dimension is limited according to the value of the request parameter username
-
Let's open two command lines and send requests at the same time (the action should be fast). The first username is equal to Tom and the second is equal to Jerry. Theoretically, if they are completed in 8 seconds, 900 requests for each command can succeed
-
The test results are shown in the figure below. It can be seen that it meets the expectations. Each username uses its own token:
- So far, the current limiting practice of Spring Cloud Gateway has been completed. Such a simple and easy-to-use current limiting scheme is expected to bring reference to your study and use
You're not alone. Xinchen's original accompanies you all the way
- Java series
- Spring collection
- Docker series
- kubernetes series
- Database + middleware series
- DevOps series
Welcome to the official account: programmer Xin Chen
Wechat search "programmer Xinchen", I'm Xinchen, looking forward to traveling with you in the Java World
https://github.com/zq2599/blog_demos