Redis combate 9 ID único global

Al emitir cupones, cada tienda puede emitir cupones. Cuando los usuarios se apresuran a comprar, si la ID en la tabla de cupones usa la ID de aumento automático de la base de datos, habrá los siguientes problemas:

1: La ley de la identificación es demasiado obvia, fácil de cepillar

2: cuando la cantidad de datos es grande, estará limitada por los datos de una sola tabla

Análisis de escenarios de desventaja:

Escenario de regla de identificación: si nuestra identificación tiene reglas demasiado obvias, los usuarios o los oponentes comerciales pueden adivinar fácilmente parte de nuestra información confidencial, como cuántos pedidos vendió el centro comercial en un día, lo que obviamente es inapropiado.

Limitación de tabla única: a medida que la escala de nuestro centro comercial se vuelve cada vez más grande, la capacidad de una sola tabla mysql no debe exceder los 500 W. Después de que la cantidad de datos sea demasiado grande, necesitamos dividir la base de datos y la tabla, pero después de dividir la tabla , lógicamente Son la misma tabla, por lo que sus ID no pueden ser los mismos, por lo que debemos garantizar la unicidad de los ID.

Generador de ID global

El generador de ID global es una herramienta que se utiliza para generar un ID único global en un sistema distribuido. Generalmente, las siguientes características deben ocultarse:

Exclusividad, alta disponibilidad, incrementalidad, seguridad, alto rendimiento

Estrategia de generación de ID única a nivel mundial:

UUID, incremento automático de Redis, algoritmo de copo de nieve, incremento automático de base de datos

Estrategia de ID de incremento automático de Redis:

1: una tecla por día, conveniente para contar pedidos;

2: las ID son todas las marcas de tiempo + contadores

Combate real: obtenga una identificación única a nivel mundial al unir otra información basada en Redis

El ID único global es de tipo largo y la marca de tiempo se basa en un momento determinado. Por ejemplo, podemos usarlo durante 69 años a partir del 2022.11.26 23:00:00.

Pensamiento 1: Obtener el segundo de la hora actual:

Pensamiento 2: ¿Cómo se calcula la marca de tiempo?

Usar segundos desde la hora actual - segundos desde la hora inicial

Pensamiento 3: ¿Cómo configurar el número de serie?

Use el comando setnx de Redis, lo mejor es agregar el año, mes y día actual

Pensamiento 4: ¿Cómo empalmar?

Debido a que lo que necesitamos devolver es de tipo largo, si usa el empalme de cadenas, debe convertirlo. También sepa que al usar el empalme de cadenas, cuando la cantidad de simultaneidad es grande, también habrá problemas de rendimiento. Entonces, ¿cómo debemos lidiar con eso?

Nota: Veamos nuevamente el formato de la ID única global. Como se muestra en la figura anterior, podemos ver que hay 64 bits en total, de los cuales el bit de signo es 1 y la marca de tiempo es de 31 bits. El número de serie tiene 32 dígitos, ¿has encontrado algo? Si movemos la marca de tiempo a la izquierda 32 bits (porque el número de serie es de 32 bits. Mueva la posición a la izquierda para dejar espacio para el número de serie), ¿es el bit de signo + la marca de tiempo?

1: También sabemos que el movimiento más rápido hacia la izquierda en la computadora es x<< dígitos.

2: También necesitamos saber que en la computadora | o cálculo: operación OR bit a bit "|"

De acuerdo a lo anterior, podemos saber que después del número de serie de la operación del bit, se encuentra el valor del número de serie. Sea cual sea el número de serie, eso es todo.

Por tanto, podemos saber que el código de empalme es el siguiente: timeStamp << 32 |no;

Código definitivo:

importar org.springframework.data.redis.core.StringRedisTemplate; 
importar org.springframework.stereotype.Component; 
 
importar java.time.LocalDateTime; 
importar java.time.ZoneOffset; 
importar java.time.format.DateTimeFormatter; 
 
/** 
 * @author 凯哥Java 
 * @description 基于Redis实现62位的全局唯一ID 
 * @company 
 * */ 
@Component 
public class RedisIdWorker { 
 
    private static final long BEGIN_TIMESTAMP = 1669503600L; 
 
 
    StringRedisTemplate final privado stringRedisTemplate; 
 
    /** 
     * 序列号的位数
     */ 
    private static final int COUNT_BITS = 32; 
 
    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate; 
    }
 
    /** 
     * Obtener id 
     * @param kyePrefix 
     * @return 
     */ 
    public long nextId(String kyePrefix){ 
        //1: Marca de tiempo de generación = marca de tiempo actual - marca de tiempo de inicio 
        LocalDateTime now = LocalDateTime.now(); 
        long nowSecond = now.toEpochSecond (ZoneOffset.UTC); 
        long timeStamp = nowSecond - BEGIN_TIMESTAMP; 
 
        //2: Genere un número de serie. Use sexNx. Agregue el año, mes y día actual 
        //Obtenga su hora, mes y día actual 
        String date = now.format (DateTimeFormatter.ofPattern("yyyy:MM:dd")); 
        //Iniciar número de serie de 32 bits 
        long no = stringRedisTemplate.opsForValue().increment("icr:"+kyePrefix+":"+date); 
    } 
    /** 
        //3: retorno de empalme
        return timeStamp << COUNT_BITS |no; 
        Tarea ejecutable = ()->{
 
     * Obtener milisegundos para la hora especificada 
     * @param args 
     */ 
    public static void main(String[] args) { 
        LocalDateTime time = LocalDateTime.of(2022,11,26,23,00,00); 
        long second = time.toEpochSecond (ZoneOffset.UTC); 
        System.out.println(segundo); 
 
    } 
} 
 
Prueba: usar subprocesos múltiples y cierre de cuenta regresiva 
private ExecutorService executorService = Executors.newFixedThreadPool(500); 
 
    @Resource 
    private RedisIdWorker redisIdWorker; 
 
    @Test 
    public void RedisIdWorkerTest() lanza la opción InterruptedExce { 
        CountDownLatch latch = new CountDownLatch(300);
            for(int i = 0;i<100;i++){ 
                long id = redisIdWorker.nextId("myorder"); 
                Sistema.salida.println(id); 
            } 
            latch.countDown(); 
        }; 
 
        comienzo largo = System.currentTimeMillis(); 
        for(int i = 0;i< 300;i++){ 
            executorService.submit(tarea); 
        } 
        cerrojo.esperar(); 
        long endTime = System.currentTimeMillis(); 
        System.out.println("耗时:"+(endTime-begin)); 
    }

Supongo que te gusta

Origin blog.csdn.net/kaizi_1992/article/details/128784616
Recomendado
Clasificación