java - envío repetitivo - frecuencia de solicitud de límite - bloqueo distribuido redis


1. Introducción a la escena

1. Limite la frecuencia de solicitud de una interfaz. El mismo usuario solo puede solicitar una vez en 3 segundos. La interfaz es una interfaz común, que es más o menos el caso.
Inserte la descripción de la imagen aquí
2. Usaré Apache AB como herramienta de prueba. Si no lo ha instalado, puede consultar este artículo. Comando del portal


AB:
-C: establece el JSESSIONID solicitado
-n: número de solicitudes
-c: número de concurrentes

ab -C "JSESSIONID=7E41844F9D1D5CD6910C5B161C8D8934"  -n100 -c100 http://127.0.0.1:8081/tomorrow/pay/test

2. Candado distribuido de Redis

Permíteme quejarme primero. Vi muchos escritos en Internet que usan el método set de redis. Dios mío, ¿qué quieres? Redis es rápido, ¡pero el valor de la clave SET no puede resolver el problema en absoluto! ! !
En este lugar usamos bloqueos distribuidos de Redis, de hecho, este bloqueo distribuido todavía se usa bastante. No es que el viejo no te mienta, ¡jaja!
SETNX: Si la clave dada ya existe, SETNX no realizará ninguna acción. Si la configuración es correcta, devuelve 1; si la configuración falla, devuelve 0.
Primero mire un párrafo:
Inserte la descripción de la imagen aquí
Nuestro lugar es básicamente el mismo que las ideas anteriores. Pegue el código directamente:
debe prestar atención a la versión correspondiente: versión SpringBoot

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.serializer.RedisSerializer;
import redis.clients.jedis.Protocol;
import redis.clients.util.SafeEncoder;
import java.io.Serializable;

  /**
     * 创建 SETNX
     * @param key key
     * @param value value
     * @param expire 过期时间 秒
     * @return
     */
    public boolean setSetNX(String key, Serializable value, long expire) {
        Boolean result = (Boolean) redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis (RedisConnection connection) throws DataAccessException {
                RedisSerializer valueSerializer = redisTemplate.getValueSerializer();
                RedisSerializer keySerializer = redisTemplate.getKeySerializer();
                Object obj = connection.execute(
                        "set",
                        keySerializer.serialize(key),
                        valueSerializer.serialize(value),
                        SafeEncoder.encode("NX"),
                        SafeEncoder.encode("EX"),
                        Protocol.toByteArray(expire)
                );
                return obj != null;
            }
        });
        return result;
    }
package com.tomorrow.controllers;

import com.tomorrow.commons.redis.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author Tomorrow
 * @date 2020/3/16 0:19
 */
@RestController
public class TestController {
    // 这里这是测试,我随便起的KEY,实际可以更改为用户的ID
    private final static String REDIS_KEY = "TEST_KEY";

    @Autowired
    private RedisUtil redisUtil;

    @RequestMapping("/test")
    public Object callBackPayTabs(HttpServletRequest request) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HHmmss");
        String currentTime = simpleDateFormat.format(new Date());
        
        if (!redisUtil.setSetNX(REDIS_KEY, currentTime, 3)) {
            System.out.println("被拦截啦:" + simpleDateFormat.format(new Date()));
            return "FAIL";
        }
        System.out.println("成功啦:------------------------------" + simpleDateFormat.format(new Date()));
        return  "SUCCESS";
    }
}

El número de solicitudes es: 12000 y el número de concurrentes: 500
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

3 、 sesión

package com.tomorrow.controllers;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author Tomorrow
 * @date 2020/3/16 0:19
 */
@RestController
public class TestController {
    // 这里这是测试,我随便起的KEY,实际可以更改为用户的ID
    private final static String REDIS_KEY = "TEST_KEY";

    @RequestMapping("/test")
    public Object callBackPayTabs(HttpServletRequest request) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HHmmss");
        String currentTime = simpleDateFormat.format(new Date());

        Object attribute = request.getSession().getAttribute(REDIS_KEY);
        if (attribute != null) {
            // 判断现在时间与上次存入session的时间,间隔是否小于3秒
            if ((Integer.valueOf(currentTime) - Integer.valueOf(String.valueOf(attribute))) < 3) {
                System.out.println("被拦截啦:" + simpleDateFormat.format(new Date()));
                return "FAIL";
            }
        }
        request.getSession().setAttribute(REDIS_KEY, currentTime);

        System.out.println("成功啦:------------------------------" + simpleDateFormat.format(new Date()));
        return  "SUCCESS";
    }
}

Prueba de esfuerzo de usuario AB:
la cantidad de solicitudes que configuré aquí es: 50000 y la cantidad de solicitudes simultáneas: 20000. La solicitud es demasiado rápida, de lo contrario, el efecto no se puede mostrar, jajaja
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
, está bien, entonces esta situación se puede manejar a través de la sesión. Pero no se recomienda la sesión

// 设置session过期时间,3秒钟,只对该session
request.getSession().setMaxInactiveInterval(3);

4. Cola

¡Agrégalo más tarde! ! ! Ser perezoso



5. Charla miscelánea

1. AB especificar encabezados
-H: especificar encabezados

ab -H "client:xxx" -H "token:ac7dbf4aa47f907e1c70409619f11c82" -H "uid:10004" -C "JSESSIONID=4EB88881AEF4079A59765B401EE94847"  -n100 -c100 http://127.0.0.1:8081/p123rrowOne

2. Lo anterior es mi prueba de presión local. Redis es local. Si es un servidor, no lo configure tan grande. Tiene que ir paso a paso. Presione 50,000 a 20,000. Es posible que el servidor no pueda soportarlo. .
3. Lo anterior es solo una lista. Liezi, da una idea, se puede optimizar en la práctica, como agregar AOP, todo esto es posible
4. Si se hace este tipo de restricción, de hecho, lo más importante para considerar es el intervalo de tiempo, como el método de conjunto de Redis. Es rápido, pero no puede resolver el problema. Dado que es una restricción, debe considerar este problema.
5. Si utiliza el método de conjunto de Redis para prueba, la cantidad de solicitudes y la cantidad de simultaneidad se pueden establecer un poco más grandes, y luego se puede reproducir lo que dije anteriormente.En este caso
6, entonces no hay nada que decir, debería ser un java, así que no lo hice escríbelo en detalle, perdóname






Proporcione un grupo: 807770565, bienvenidos a todos a entrar y charlar
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_38637558/article/details/104890203
Recomendado
Clasificación