Sistema de picos-springboot, mysql, redis

Proceso paso a paso

1. Construcción del entorno

1. 1 Estructura del directorio

Inserte la descripción de la imagen aquí

1,2 sql

create table product(
    id            int(12)        not null auto_increment comment 'id',
    product_name  varchar(60)    not null comment '商品名称',
    stock         int(10)        not null comment '库存',
    price         decimal(16,2)  not null comment '单价',
    version       int(10)        not null default 0 comment '版本号,乐观锁',
    primary key (id)
);


-- 购买记录表
create table purchase_record(
    id             int(12)        not null auto_increment comment ,
    user_id        int(12)        not null comment '用户编号',
    product_id     int(12)        not null comment '商品编号',
    price          decimal(16,2)  not null comment '价格',
    quantity       int(12)        not null comment '数量',
    sum            decimal(16,2)  not null comment '总价',
    purchase_date  timestamp      not null default now() comment '购买日期',
    primary key (id)
);

Servicio:

  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void seckillbyId(Integer id) {
        Product product = productMapper.getById(id);
        if (product .getStock() > 0) {
            productMapper.decreaseStock(id);
        } else {
            System.out.println("库存不足");
        }
    }

mapeador:

@Update("update product set stock=stock-1 where id = #{id}")
public int decreaseStock(@Param("id") int id);

2. Bases teóricas

Inserte la descripción de la imagen aquí
La imagen proviene de: https://www.cnblogs.com/SteadyJack/p/11228391.html
Este artículo realiza una versión simplificada

1. Le bloqueo pesimista entender el principio
ver
2. Prueba de presión utilizando JMeter fundamental
Ver
3.redisTemplate uso básico
Ver
4. pico conceptos de diseño del sistema
de aguja ideas de optimización arquitectura del sistema
pico Arquitectura de Referencia

3. Basado en Mysql + Mybatis

3.1 Situación básica

Probé varios grupos, y no ha habido una situación de sobreenvío. Solo puedo seguir modificando y aumentando el número de subprocesos. Finalmente siento que no es suficiente reducir uno a la vez, así que cambié el código a lo siguiente:

  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void seckillbyId(Integer id) {
        Product product = productMapper.getById(id);
        //增加随机数
        int i = new Random().nextInt(10);
        if (product .getStock() > 0) {
            productMapper.decreaseStock(id, i);
        } else {
            System.out.println("库存不足");
        }

    }
  @Update("update product set stock=stock-#{decrease} where id = #{id}")
    public int decreaseStock(@Param("id") int id, @Param("decrease") int quantity);

Datos originales de la base de datos:
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Chaofa primera vez:
Inserte la descripción de la imagen aquí
Chaofa segunda vez:
Inserte la descripción de la imagen aquí
De hecho, todos sabemos que el método de verificar directamente si es 0 y luego reducir el inventario definitivamente no es posible, con el propósito de probar si la prueba es factible y si se puede probar. Si hay una situación de súper cabello, de lo contrario, un método incorrecto no puede aparecer súper cabello, ¡y no tienes que jugarlo más tarde!

3.2 Basado en un bloqueo optimista

El bloqueo optimista es mirar antes y después modificar el valor actual es el valor y si me sale el mismo, si no el mismo que se explica, otros modificados, a continuación, voy a cambiar este valor puede ser error de modificación simultánea se produce.
Por lo tanto, Cada vez que quiera reducir el inventario, veré si el número de versión que obtuve antes de que se haya modificado el cambio,
es decir , el siguiente es el código de clave modificado:

 @Update("update product set stock=stock-#{decrease} , version = version +1 where id = #{id} and version=#{version}")
    public int decreaseStockByOptimisticLock(@Param("id") int id, @Param("decrease") int quantity, @Param("version") int version);

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void seckillbyId(Integer id) {
        Product byId = productMapper.getById(id);
        int i = new Random().nextInt(10);
        if (byId.getStock() > 0) {
//            productMapper.decreaseStock(id, i);
            productMapper.decreaseStockByOptimisticLock(id,i,byId.getVersion());
        } else {
            System.out.println("库存不足");
        }

    }

Luego prueba:
Sin embargo:
Inserte la descripción de la imagen aquí
sí, ¿el
problema está supervisado?
... Si lo lees detenidamente, deberías poder encontrarlo. Si no lo encuentras, puedes pensarlo.
No hablaré sobre la causa del error: el
código revisado es el siguiente:

 @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void seckillbyId(Integer id) {
        Product byId = productMapper.getById(id);
        int i = new Random().nextInt(10);
        if (byId.getStock() > 0 && byId.getStock() >= i) {
//            productMapper.decreaseStock(id, i);
            productMapper.decreaseStockByOptimisticLock(id, i, byId.getVersion());
        } else {
            System.out.println("库存不足");
        }
    }

Prueba de nuevo:
Inserte la descripción de la imagen aquí
! Oh bonito
! Pero eso es sólo la primera vez, hay una posibilidad simultánea Oh, yo recuerdo a mí mismo que
valoro cada vez antes y después de la base de datos se publican
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
modificado de nuevo:
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Orie no pareció !!! super
venido a un gran:
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
???
no soy un conjunto de 5000 que no tiene mucho sentido en una prueba?

3.2 Basado en bloqueo pesimista

¿Cómo lograr un bloqueo pesimista?
La forma más fácil es agregar un sincronizado, cuando un hilo mantiene el bloqueo, otros hilos no pueden obtener el
código de bloqueo es el siguiente:

   @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public synchronized void  seckillbyId(Integer id) {
        Product byId = productMapper.getById(id);
        int i = new Random().nextInt(10);
        if (byId.getStock() > 0 && byId.getStock() >= i) {
            productMapper.decreaseStock(id, i);
//            productMapper.decreaseStockByOptimisticLock(id, i, byId.getVersion());
        } else {
            System.out.println("库存不足");
        }
    }

jconsole dijo lo siguiente:
primera vez:
memoria de montón:

Inserte la descripción de la imagen aquí
Hilo:
Inserte la descripción de la imagen aquí

Volviendo a probar el bloqueo optimista, el rendimiento de la jconsola del bloqueo optimista es el siguiente:
Inserte la descripción de la imagen aquí

4. Basado en Redis

A partir del bloqueo optimista y el bloqueo pesimista implementado anteriormente, podemos ver que:
1. El bloqueo optimista realmente ejerce presión sobre la base de datos, y uno intenta escribir uno
2. La presión del bloqueo pesimista en la base de datos solo es
visible después de una verificación y una escritura precisa . La presión sobre la base de datos que usa bloqueos pesimistas es menor que la de los bloqueos optimistas, pero el uso de bloqueos pesimistas en realidad convierte la operación de reducción de inventario en una serie, ya sea que realmente esté preocupado por el rendimiento, y en un entorno de pico, entra de inmediato. Solicitudes múltiples, debería llevar poco tiempo completar un pico, por lo que hemos pensado en cómo compartir la presión de la base de datos, mejorar la velocidad de respuesta y aumentar el rendimiento.

Por supuesto, todo esto se basa en el hecho de que no debe ser sobrevendido;

Como todos sabemos, la velocidad de lectura y escritura de la memoria es mucho mayor que la velocidad del disco,
entonces ,
¿cómo optimizarla con redis como capa de caché ?

  • Si el inventario restante de la base de datos leída se puede transferir a redis
  • Si el número de versión se puede transferir a redis

Obviamente, todos ellos se pueden poner en el caché de redis;
de hecho, es poner la operación de mysql en redis, y esperar el final de la segunda muerte, luego sincronizar nuevamente con la base de datos

Por supuesto, lo anterior es mi idea personal,
lo examinaré después de un tiempo para mejorar la redacción de esta parte del código;

Publicado 37 artículos originales · ganado elogios 6 · vistas 4643

Supongo que te gusta

Origin blog.csdn.net/littlewhitevg/article/details/105490867
Recomendado
Clasificación