Maison  >  Article  >  Java  >  Limitation du courant d'interface, toutes les opérations intéressantes sont ici !

Limitation du courant d'interface, toutes les opérations intéressantes sont ici !

Java学习指南
Java学习指南avant
2023-07-26 14:22:331139parcourir

Pourquoi la limitation de courant

Lors de la conception du système, nous aurons une capacité estimée du système. Si elle dépasse le seuil TPS/QPS que le système peut supporter pendant une longue période, le système peut être submergé. ce qui finit par rendre l'ensemble du service non disponible. Afin d'éviter cette situation, nous devons limiter le flux de demandes d'interface.

Ainsi, nous pouvons protéger le système ou éviter un gaspillage inutile de ressources en limitant le taux de demandes d'accès simultanées ou le nombre de demandes dans une fenêtre de temps. Une fois la limite de débit atteinte, nous pouvons refuser le service, faire la queue ou attendre.

Contexte limitant actuel

Le système dispose d'une interface pour obtenir les codes de vérification SMS des téléphones portables, car il s'agit d'une interface ouverte, afin d'éviter que les utilisateurs n'envoient constamment des demandes pour obtenir des codes de vérification et empêcher les tentatives malveillantes de balayage. l'interface, nous utilisons la dernière méthode de compteur simple pour limiter le flux actuel, limitant chaque IP à une seule requête par minute, puis la limite de fenêtre de temps de chaque autre numéro de téléphone mobile est jugée par la logique métier. Généralement, certaines interfaces ont un nombre de visites relativement important et peuvent saturer le système, il faut donc ajouter des restrictions de circulation ! Tels que : vente flash, etc...

Méthode d'implémentation

1 Présentation des dépendances

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

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

2.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter {
    /**
     * 限流key
     */
     String key() default Constants.RATE_LIMIT_KEY;

    /**
     * 限流时间,单位秒
     */
     int time() default 60;

    /**
     * 限流次数
     */
    int count() default 100;

    /**
     * 限流类型
     */
    LimitType limitType() default LimitType.DEFAULT;

    /**
     * 限流后返回的文字
     */
    String limitMsg() default "访问过于频繁,请稍候再试";
}

3.Débit limité section
@Aspect
@Component
public class RateLimiterAspect {

    private final static Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);

    @Autowired
    private RedisUtils redisUtils;

    @Before("@annotation(rateLimiter)")
    public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable {
        int time = rateLimiter.time();
        int count = rateLimiter.count();
        long total = 1L;

        String combineKey = getCombineKey(rateLimiter, point);
        try
        {
            if(redisUtils.hasKey(combineKey)){
                total = redisUtils.incr(combineKey,1);  //请求进来,对应的key加1
                if(total > count)
                    throw new ServiceRuntimeException(rateLimiter.limitMsg());
            }else{
                redisUtils.set(combineKey,1,time);  //初始化key
            }
        }
        catch (ServiceRuntimeException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ServiceRuntimeException("网络繁忙,请稍候再试");
        }
    }

    /**
     * 获取限流key
     * @param rateLimiter
     * @param point
     * @return
     */
    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
        StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
        if (rateLimiter.limitType() == LimitType.IP)
        {
            stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
        }
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclaringClass();
        stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
        return stringBuffer.toString();
    }

}

4. Écrivez une interface simple pour tester
@RestController
public class TestController {

    @RateLimiter(time = 60, count = 1, limitType = LimitType.IP, limitMsg = "一分钟内只能请求一次,请稍后重试")
    @GetMapping("/hello")
    public ResultMsg hello() {
        return ResultMsg.success("Hello World!");
    }
}

5. ee

6 . Tests d'interface

1) La première fois que vous l'enverrez, le résultat sera renvoyé normalement

Limitation du courant d'interface, toutes les opérations intéressantes sont ici !

2) La deuxième fois que vous l'enverrez dans la minute, vous obtiendrez une erreur et une invite de limite actuelle

Limitation du courant d'interface, toutes les opérations intéressantes sont ici !

Le ci-dessus est la AOP + Redis solution pour mettre en œuvre la limite de courant de l'interface, vous avez perdu vos études ?

Il existe d'autres méthodes de limitation de courant, telles que la méthode de limitation de courant par fenêtre coulissante (plus rigoureuse que le compteur), le seau à jetons, etc... Les amis intéressés peuvent en apprendre davantage.


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer