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 ~~~~