Spike scenario: how to reduce inventory through Redis

Click on "end of life", pay attention to the official account.

Daily technical dry goods, delivered at the first time!

 

 

Redis pre inventory reduction

 

The main idea is to reduce the access to the database, reduce the inventory before, directly access the database and read the inventory. When high concurrent requests come, a large amount of read data may lead to the collapse of the database.

 

Idea:

 

  • When the system is initialized, the commodity inventory is loaded into Redis cache and saved

  • When receiving the request, Redis will get the inventory value of the commodity and pre reduce the inventory. If the inventory is insufficient after reduction, it will directly return the logical Exception. There is no need to access the database to reduce the inventory. If the inventory value is correct, proceed to the next step

  • Enter the request into the queue and immediately return a value to the front end, indicating that it is queuing, and then perform the second kill logic. The back-end queue performs the second kill logic. The front end polls the requests sent by the back-end. If the second kill is successful, it returns the second kill. If it is successful, it returns the failure.

  • (the back end requests a single thread to leave the queue, generate orders, reduce inventory and follow logic) the front end polls at the same time

  • Front end display

 

Step 1: pre reduce inventory

 

/**
 * Second kill interface optimization - step 1: put all commodity inventory into cache after system initialization
 */
@Override
public void afterPropertiesSet() throws Exception {
    List<GoodsVo> goods = goodsService.getGoodsList();
    if (goods == null) {
        return;
    }
    for (GoodsVo goodsVo : goods) {
        redisService.set(GoodsKey.getGoodsStock, "" + goodsVo.getId(), goodsVo.getStockCount());
        isOverMap.put(goodsVo.getId(), false);//First initialize that each product is false, that is, there are
    }
}
/**Optimization of second kill interface -- step 2: pre reduce inventory and reduce inventory from cache
 * Use the method in redis to subtract inventory, and the return value is the value after subtracting 1
 * */
long stock = redisService.decr(GoodsKey.getGoodsStock, "" + goodsId);
/*The judgment here cannot be less than or equal to, because after subtraction, it indicates that there is a normal range*/
if (stock < 0) {
    isOverMap.put(goodsId, true);//If there is no inventory, set the map of the corresponding id commodity to true
    return Result.error(CodeMsg.MIAO_SHA_NO_STOCK);
}

 

Pre reduced inventory:

 

1. First read out all data, initialize it into the cache, and store it in Redis in the form of stock + goodid

 

2. During the second kill, the pre reduction inventory is detected first. From redis, the inventory of the corresponding commodity is subtracted by decr. If the inventory is less than 0, it indicates that the inventory is insufficient at this time, and there is no need to access the database. Just throw an exception directly.

 

Memory tag:

 

Due to interface optimization, there are many Redis based cache operations. When the concurrency is high, it will also bring a great burden to the Redis server. If the access to the Redis server can be reduced, the optimization effect can also be achieved.

 

Therefore, you can add a memory map to mark whether the inventory of the corresponding goods is still available. Before accessing Redis, get the inventory mark of the corresponding goods in the map, and you can judge that there is no inventory without accessing Redis.

 

1. Generate a map, and store the id of all products as the key and mark false in the map during initialization.

 

private Map<Long, Boolean> isOverMap = new HashMap<Long, Boolean>();

/**
 * Second kill interface optimization - step 1: put all commodity inventory into cache after system initialization
 */
@Override
public void afterPropertiesSet() throws Exception {
    List<GoodsVo> goods = goodsService.getGoodsList();
    if (goods == null) {
        return;
    }
    for (GoodsVo goodsVo : goods) {
        redisService.set(GoodsKey.getGoodsStock, "" + goodsVo.getId(), goodsVo.getStockCount());
        isOverMap.put(goodsVo.getId(), false);//First initialize that each product is false, that is, there are
    }
}
    /**Re Optimization: after optimizing the inventory, the request does not access redis and judges the value of the corresponding map
     * */
    boolean isOver = isOverMap.get(goodsId);
    if (isOver) {
        return Result.error(CodeMsg.MIAO_SHA_NO_STOCK);
    }


    if (stock < 0) {
        isOverMap.put(goodsId, true);//If there is no inventory, set the map of the corresponding id commodity to true

 

2. Before pre reducing inventory, get the mark from the map. If the mark is false, it indicates inventory

 

3. Pre decrease inventory: when the inventory is insufficient, set the mark of the commodity to true, indicating that the inventory of the commodity is insufficient. In this way, all the following requests will be intercepted without accessing redis to pre reduce inventory.

 

 

PS: in case you can't find this article, you can collect some likes for easy browsing and searching.

Keywords: Programmer

Added by retoto on Thu, 20 Jan 2022 05:50:51 +0200