preface

A friend has been sending me messages asking me about the order and inventory disposal plan under the scenario of high concurrency. Recently, I have been busy because of overtime work, so I haven’t had time to reply. Today, I think it is better to write an article to list all these, so that we can learn, say ten thousand are not as full of dry goods to the reality, dry goods are below!

introduce

Premise: Distributed system, high concurrency scenario With 100 inventory of goods A, now 1000 or more users to buy. How to keep inventory safe in high concurrency scenarios. Expected results: 1. Not oversold 2. Not many sellers 3. Fast response to order 4

Ordering idea:

  1. When placing an order, the order is generated, the inventory is reduced, and the inventory flow is recorded at the same time. In this case, the inventory operation needs to be carried out first to regenerate the order data, so that the inventory modification is successful. In the special case of timeout response, the final consistency can also be completed through the fourth step to periodically check the inventory flow.
  2. The payment is successful to delete the inventory flow, and the deletion after processing can make the inventory flow data table less data and easier to maintain.
  3. Cancel order without payment, return stock + delete stock flow
  4. Periodically check the inventory flow and respond to the order status to ensure the final consistency

(There is a separate stock flow for the return order, insert the stock flow for the return order, delete the stock flow and return the stock after the return order is completed)

When will we reduce inventory

  • Plan 1: reduce inventory when adding purchase.
  • Plan 2: Confirm order page to reduce inventory.
  • Plan 3: Reduce inventory when submitting an order.
  • Plan 4: reduce inventory at time of payment.

Analysis:

  • Scheme 1: Adding to the shopping cart at this time does not mean that the user will definitely buy. If the inventory is processed at this time, the user who wants to buy will be displayed as out of stock. And people who don’t want to buy have been hogging inventory. Obviously this approach is not desirable. Vipshop shopping car lock inventory, but they are another practice, after adding a certain period of time, will be removed from the cart.
  • Scheme 2: Confirmation order page the user has the desire to buy, but does not submit the order at this time, reducing inventory will increase great complexity, and the function of the confirmation order page is to let the user confirm information, reducing inventory is unreasonable, I hope everyone to express opinions on this plan, I only think so much for the time being.
  • Plan 3: Reduce inventory when submitting an order. The user chooses to submit the order, indicating that the user has a strong desire to buy. There will be a time to pay when the order is generated, such as half an hour. After more than half an hour, the system automatically cancels the order and returns the inventory.
  • Plan 4: reduce inventory when payment. For example: only 100 users can pay, 900 users can’t pay. Poor user experience with 900 invalid order data generated at the same time.

Therefore, to sum up, plan 3 is reasonable.

Double order problem

  1. Users click too fast and submit again.
  2. The network is delayed and the user submits the file repeatedly.
  3. Some frameworks automatically retry when network latency is high, resulting in repeated requests.
  4. The user acts maliciously.

The solution

  1. Front end intercept, click the back button to set ash.

  2. Background: (1) Redis prevents repeated clicking and obtains the user’s token before placing an order. When placing an order, the background system verifies whether the token is valid, resulting in the problem that one user and multiple devices cannot place an order at the same time.

//key, wait for lock, lock time redis.lock("shop-oms-submit" + token, 1L, 10L);

Copy the code

A user with multiple devices can place an order at the same time.

//key, wait for lock, lock time redis.lock("shop-oms-submit" + token + deviceType, 1L, 10L);

Copy the code

(2) To prevent malicious users, malicious attacks: one minute call orders more than 50 times, join the temporary blacklist, 10 minutes after the operation can be continued, one hour to allow a weak cross-period verification. Use the list structure of REids with an expiration time of one hour

/**
     * @param token
     * @return true*/ public Boolean judgeUserToken(String token) {// Obtain user order times 50 times 1 minute String blackUser ="shop-oms-submit-black-" + token;
        if(redis.get(blackUser) ! = null) {return false;
        }
        String keyCount = "shop-oms-submit-count-" + token;
        Long nowSecond = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+ 8")); Long count = redis.rpush(keyCount, string.valueof (nowSecond), 60 * 60);if (count < 50) {
            return true; List<String> secondString = redis.lrange(keyCount, count - 50, count - 49); Long oldSecond = Long.valueOf(secondString.get(0)); Boolean result = nowSecond.compareTo(oldSecond + 60) > 0;if(! Redis. Set (blackUser, string.valueof (nowSecond), 10 * 60); }return result;
    }

Copy the code

How to reduce inventory safely

Multi-user buying, how to achieve concurrent safety inventory reduction?

  • Option 1: Database operation commodity inventory using optimistic lock to prevent oversold:
sql:update sku_stock set stock = stock - num where sku_code = ' ' and stock - num > 0;

Copy the code

Analysis: In a high concurrency scenario, assume that there is only one item in stock and two requests come in at the same time to snap up the item. The database level will limit only one user to successful inventory. You can do this if the amount of concurrency is not very high. But if it’s a second kill, a rush, a high instantaneous flow, the pressure will all go to the database, may bring down the database.

  • Scheme 2: Use Redis single thread to enforce serial processing
/** * Disadvantages of the concurrency is not high, only one user preemption operation at the same time, user experience is not good! * * @param orderSkuAo */ public boolean subtractStock(OrderSkuAo orderSkuAo) { String lockKey ="shop-product-stock-subtract" + orderSkuAo.getOrderCode();
        if(redis.get(lockKey)){
            return false; } try { lock.lock(lockKey, 1L, 10L); }catch (Exception e){logutil.error ("e=",e);
        }finally {
            lock.unLock(lockKey);
        }
        return true;
    }

Copy the code

Analysis: The use of Redis distributed lock, forced control of the same commodity processing request serialization, shortcomings of low concurrency, slow processing, not suitable for buying, high concurrency scenarios. Poor user experience, but reduced pressure on the database.

  • Scheme 3: Redis + MQ + mysql ensures stock security and meets high concurrency processing, but it is relatively complex.
* @param orderCode * @param skuCode * @param num * @return
     */
    public boolean subtractStock(String orderCode,String skuCode, Integer num) {
        String key = "shop-product-stock" + skuCode;
        Object value = redis.get(key);
        if(value == null) {// If the item inventory is placed in the cache in advance, if the cache does not exist, the item is regarded as missingreturn false; Integer stock = (Integer) value;if (stock < num) {
            LogUtil.info("Out of stock");
            return false; } // The database is not safe because the key of redis has been changed by other threads. // The database is not safe. Long newStock = redis.increment(key, -num.longValue()); // The stock is sufficientif (newStock >= 0) {
            LogUtil.info("Successful buying"); //TODO can use MQ to synchronize data between Redis and mysql to reduce response time}elseRedis.increment (key, num. LongValue ()); LogUtil.info("Out of stock, concurrent");
            return false;
        }
        return true;
    }

Copy the code

Analysis: Atomic operation of Redis Increment is utilized to ensure inventory security and high concurrent response time is guaranteed by MQ. However, you need to save the inventory information to Redis, and ensure that Redis and Mysql data synchronization. The disadvantage is that you can’t place orders after Redis is down. Increment is an atomic operation.

From what has been discussed above:

Scheme 3 can meet the processing of hot commodities such as second kill and high concurrent buying, and the real inventory reduction and order can be carried out asynchronously. When the concurrency is not high, we can use the optimistic lock of the database in scheme 1 for common goods or the normal purchase process, or redesign scheme 3 to support multiple goods in a single order, but the complexity is increased, and the consistency of data between Redis and mysql needs to be checked regularly.

Order time-out issues exceed order validity, order cancels, inventory can be rolled back using MQ or other solutions.

Set the cron expression timed task MQ message delay queue to check Spring Task periodically

Order and inventory related to several important knowledge

TCC model: Try/Confirm/Cancel: After placing an order and reducing the inventory, order data will be generated. If the inventory is successfully deducted due to timeout but the return fails, data will be recovered through periodic task check. If the number of times of data execution exceeds a certain limit, manual rollback will be performed. The same goes for restocking. Midempotency: How to ensure the midempotency of the external interface in the distributed high concurrency system, recording the inventory flow is a solution to realize the inventory rollback, support the midempotency, order number +skuCode is the unique primary key (table modification frequency is high, less build index) optimistic lock: where stock + num>0 message queue: Redis: Limit request frequency, high concurrency solution, improve response speed Distributed lock: prevent repeated commits, prevent high concurrency, enforce serialization distributed transaction: Final consistency, synchronous processing (Dubbo)/ asynchronous processing (MQ) modification + compensation mechanism

Write the last words

You can leave a comment below to discuss what you don’t understand. You can also ask me in a private letter. After reading it, I will reply. Also welcome everyone to pay attention to my official account: bright future, Golden Three silver four job-hunting interview season, sorted out more than 1000 nearly 500 pages of PDF documents of Java interview questions, articles will be updated in it, sorted out the information will be placed in it. Finally think the article is helpful to you remember to point a thumbs-up oh, little attention not lost, there are fresh dry goods to share every day!