Heim >Java >javaLernprogramm >Schnittstellenstrombegrenzung, alle coolen Operationen sind da!

Schnittstellenstrombegrenzung, alle coolen Operationen sind da!

Java学习指南
Java学习指南nach vorne
2023-07-26 14:22:331162Durchsuche

Warum ist der Strom begrenzt?

Beim Entwurf des Systems haben wir eine geschätzte Kapazität des Systems. Wenn diese den TPS/QPS-Schwellenwert überschreitet, dem das System über einen längeren Zeitraum standhalten kann, kann es sein, dass das System überlastet wird. Dies führt schließlich dazu, dass der gesamte Dienst nicht verfügbar ist. Um diese Situation zu vermeiden, müssen wir den Fluss von Schnittstellenanfragen begrenzen.

So können wir das System schützen oder unnötige Ressourcenverschwendung vermeiden, indem wir die Rate gleichzeitiger Zugriffsanfragen oder die Anzahl der Anfragen innerhalb eines Zeitfensters begrenzen. Sobald das Ratenlimit erreicht ist, können wir den Dienst verweigern, in die Warteschlange stellen oder warten.

... Wenn die Schnittstelle nicht passiert, verwenden wir die neueste einfache Zählermethode, um den aktuellen Fluss zu begrenzen, indem jede IP auf nur eine Anfrage pro Minute begrenzt wird. Anschließend wird das Zeitfensterlimit jeder anderen Mobiltelefonnummer durch Geschäftslogik beurteilt. Im Allgemeinen weisen einige Schnittstellen eine relativ große Anzahl von Besuchen auf und können das System überlasten. Daher müssen Verkehrsbeschränkungen hinzugefügt werden! Zum Beispiel: Flash-Sale usw.

Implementierungsmethode

1. Einführung von Abhängigkeiten

<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.Begrenzter Durchfluss Abschnitt
@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. Schreiben Sie eine einfache Schnittstelle zum Testen
@RestController
public class TestController {

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

@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 业务异常
     */
    @ExceptionHandler(ServiceRuntimeException.class)
    public ResultMsg handleServiceException(ServiceRuntimeException e, HttpServletRequest request)
    {
        return ResultMsg.error(e.getMessage());
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public ResultMsg handleException(Exception e, HttpServletRequest request)
    {
        return ResultMsg.error("系统异常");
    }

}

6 . Schnittstellentests

1) Beim ersten Senden wird das Ergebnis normal zurückgegeben

Schnittstellenstrombegrenzung, alle coolen Operationen sind da!

2) Beim zweiten Senden innerhalb einer Minute erhalten Sie eine Fehlermeldung und eine Aufforderung zum aktuellen Grenzwert

Schnittstellenstrombegrenzung, alle coolen Operationen sind da!

The Oben finden Sie die AOP + Redis-Lösung zur Implementierung der Schnittstellenstrombegrenzung. Haben Sie Ihr Studium verloren?

Es gibt andere Strombegrenzungsmethoden, wie z. B. die Strombegrenzungsmethode mit Schiebefenster (strenger als der Zähler), den Token-Bucket usw. Interessierte Freunde können mehr darüber erfahren.


Das obige ist der detaillierte Inhalt vonSchnittstellenstrombegrenzung, alle coolen Operationen sind da!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:Java学习指南. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen