According ip limiting

 

There are three weapon in the development of highly concurrent systems used to protect the system: cache, degradation and limiting

    The purpose is to enhance the system buffer cache to increase access speed and the system processing capacity
    downgrade downgrade when service problems or affect the core processes, temporarily masked, to be opened after the peak or problem-solving
    purpose current limiting is achieved by limiting concurrent access / limit the rate request, or a request within the time window to protect the system speed, the rate limit is reached once the service may be denied, or waiting queue, processing demotion
 

The purpose is to enhance the system cache to increase access speed and capacity of the system can handle, can be described as anti-high concurrent flow silver bullet; degrade when service problems or affect the performance of core processes is temporarily masked, or to be peak issue to resolve after the open; and some scenes are not cached and can be demoted to solve, such as scarce resources (spike, buying), writing services (such as reviews, order), frequent complex queries (comments of the last few pages), so a means to limit the need for concurrent these scenes / request amount, i.e. the flow restrictor.

        System early in the design will have a projected capacity, longer than TPS / QPS system can withstand the threshold, the system could be overwhelmed, eventually leading to the entire service is not enough. To avoid this, we need to limit the current interface request.

       Current limiting purposes is protected by concurrent access request or a rate limit time window number of requests within the system to limit the rate, the rate limit is reached once the service may be denied, or wait queue.

        The general development of common mode current limiting high concurrency concurrency control system and controlled rate, a is the total number (for example, database connection pooling, thread pool) concurrency limits, limit the concurrent access to a rate (e.g., the nginx limit_conn module for instantaneous limit the number of concurrent connections), also can limit the number of requests per unit time window (e.g., the Guava RateLimiter, nginx limit_req the module, limiting the average rate per second). There are other restrictions, such as a remote interface call rate, MQ limit consumption rate. Also in accordance with the flow restrictor may be network connections, network traffic, CPU, or other memory load.

Solutions
using springboot + redis distributed manner limiting, custom annotation + interceptor

 1. Create a new project springboot introduced package redis

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在配置文件中配置redis

Spring:
    Redis:
      Database: 0
      Host: 127.0.0.1
      Port: 6379
      password:
      jedis:
        the pool:
          max-Active:. 8
          max the wait-: -1ms
          max-IDLE:. 8
          min-IDLE: 0
      timeout: 2000ms
2. Create a self- defined Note AccessLimit the interface used on the rear face

/ **
 * @author: Lockie
 * @date: 2019/8/13 16:09
 * @Description: limiting custom annotation
 * /
@Inherited
@Documented
@Target ({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD })
@Retention (RetentionPolicy.RUNTIME)
public @interface AccessLimit {
    / **
     * within a second specified time, API requests highest number
     * /
    int times (). 3 default;
 
    / **
     * specified time second, redis data expiration time
     * /
    int SECOND () default 10;
}
 a new interceptor, has acquired the parameters on the custom annotations, and then stored in the checksum redis

@Component
public class AccessLimitIntercept HandlerInterceptor from the implements {
    Private static Logger Logger = Final LoggerFactory.getLogger (AccessLimitIntercept.class);
 
    @Autowired
    Private StringRedisTemplate redisTemplate;
 
    / **
     * ip interface call each other before checking whether the frequent invocation interface
     * @param Request
     * @param Response
     * @param Handler
     * @return
     * @throws Exception
     * /
    @Override
    public Boolean The preHandle (the HttpServletRequest Request, Response the HttpServletResponse, Object Handler) throws Exception {
        the try {
            // Handler whether HandleMethod instance
            if (handler instanceof HandlerMethod) {
                // strong turn
                HandlerMethod HandlerMethod = (HandlerMethod) Handler;
                // acquisition method
                Method method = handlerMethod.getMethod ();
                if there are ways to determine // AccessLimit notes, some only need to do restrictor
                if (method.isAnnotationPresent (AccessLimit!. class)) {
                    return to true;
                }
 
                // get content on annotation
                accessLimit accessLimit = method.getAnnotation (AccessLimit.class);
                IF (accessLimit == null) {
                    return to true;
                }
                // Get the number of requests on the annotated method
                int times = accessLimit.times ();
                // Get request time on the annotated method
                Integer SECOND accessLimit.second = ();
 
                // splicing redis key = IP + Api limiting
                String Key = IpUtil.getIpAddr (Request) + Request.getRequestURI ();
 
                // get the redis value
                Integer maxTimes = null;
                . redisTemplate.opsForValue String value = () GET (Key);
                IF (StringUtils.isNotEmpty (value)) {
                    maxTimes Integer.valueOf = (value);
                }
                IF (maxTimes == null) {
                    // If the no ip redis time corresponding to said first call, to save key redis
                    redisTemplate.opsForValue () SET (key, ". 1", sECOND, TimeUnit.SECONDS).;
                IF the else} (maxTimes <Times) {
                    // If the time redis time is smaller than said annotation may allow access, which is a modification of the time value of redis
                    redisTemplate.opsForValue (). Set (key, maxTimes + 1 + " ", SECOND, TimeUnit.SECONDS);
                } the else {
                    // too frequent request
                    logger.info (key +" too frequent request ");
                    return setResponse (new new Results (ResultEnum.BAD_REQUEST), Response);
                }
            }
        } the catch (Exception E) {
            logger.error ( "the API request intercepted limiting abnormal, abnormality cause:", E);
            the throw new new ParameterException (E);
        }
        return to true;
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
 
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
 
    }
 
    private boolean setResponse(Results results, HttpServletResponse response) throws IOException {
        ServletOutputStream outputStream = null;
        try {
            response.setHeader("Content-type", "application/json; charset=utf-8");
            outputStream = response.getOutputStream();
            outputStream.write(JsonUtil.toJson(results).getBytes("UTF-8"));
        The catch} (Exception E) {
            logger.error ( "Method setResponse error", E);
            return to false;
        } the finally {
            IF (the outputStream = null!) {
                OutputStream.flush ();
                outputStream.close ();
            }
        }
        return to true ;
    }
}
configured interceptor, the interceptor attention to the need to inject otherwise not get the value redis inside, you can refer to the article before the interceptors could not inject redisTemplate

@Configuration
public class WebFilterConfig the implements WebMvcConfigurer {
 
    / **
     * It should first restrictor interceptor stay, or can not get to the interceptor in redistemplate
     * @return
     * /
    @Bean
    public AccessLimitIntercept getAccessLimitIntercept () {
        return new new AccessLimitIntercept ();
    }
 
    / **
     * a plurality of interceptors interceptor chain
     * @param Registry
     * /
    @Override
    public void addInterceptors (InterceptorRegistry Registry) {
        registry.addInterceptor (getAccessLimitIntercept ()) addPathPatterns ( "/ **");.
 
    }
 
 
}
Create an interface and add comments, @ AccessLimit (times = 5, second = 10) notes indicated meaning up to the same IP calls within 10 seconds of 5 times

@RestController
@RequestMapping ( "/")
public class PingController the extends BaseController {
 
    @AccessLimit (Times =. 5, SECOND = 10)
    @GetMapping (value = "/ of ping")
    public Results of ping () {
        return Succeed ( "Pong", " ");
    }
 
}
used postman at 10:00 kept at least 5 points, the sixth time will obtain a too frequent operation tips

Thumbs
----------------
Disclaimer: This article is the original article CSDN bloggers "lockie_zou", and follow CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source and link this statement.
Original link: https: //blog.csdn.net/zxl646801924/java/article/details/99442258

 

Published 168 original articles · won praise 16 · views 90000 +

Guess you like

Origin blog.csdn.net/ajax_yan/article/details/105164990