Dark Horse Dianping 02 Coupon Flash Sale (Oversold Problem)

1. Database table

2. How to generate a globally unique ID

2.1 Why does the ID not increase automatically?

Because of the above reasons, a global id generator is used.

2.2 Global ID generator (using the auto-increment function of redis)

The timestamp is the number of seconds from the set start time.

The serial number is the key of a redis string, which is mainly composed of the business key + the time of the day. The stored redis value is the order quantity on x month x day x year, which is the serial number (self-increasing).

The order number is formed by splicing, which is the order number of the current order.

The INCR command is an operation on strings. Because Redis does not have a dedicated integer type, the value stored in the key will be interpreted as a decimal 64-bit signed integer when executing the INCR command. 

package com.example.heima.utils;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

@Component
public class RedisIdWorker {
    //开始时间
    private static final long BEGIN_TIMESTAMP = 1640995200L;
    //序列号位数
    private static final int COUNT_BITS = 32;
    private StringRedisTemplate stringRedisTemplate;
    public RedisIdWorker(StringRedisTemplate stringRedisTemplate){
        this.stringRedisTemplate = stringRedisTemplate;
    }

    //id构成 : 1位符号位 + 31位时间戳 + 32位序列号
    public long nextId(String keyPrefix){
        //1.生成时间戳,当时时间
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);//时间格式转换
        long timestamp = nowSecond - BEGIN_TIMESTAMP;//计算现在距离开始时间时间差

        //2.生成32位序列号
        //2.1生成订单时间当前日期,精确到天(因为32位最多2^32次方,序列号有上限,不管多久这个key都不变。
        // 所以为了让key随时间变化,加上天数拼接,但是一天很难到达2^32单)
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        //2.2自增长(传入的是string会被redis解释成数字类型)
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);

        //3,拼接并返回
        return timestamp << 32 | count ;

    }


}

2.2.1 Testing

Analysis of the use and principle of CountDownLatch - Zhihu (zhihu.com)

//线程池500个线程
    private ExecutorService es = Executors.newFixedThreadPool(500);
    @Test
    void testIdWorker(){
        //CountDownLatch可以使一个或多个线程等待其他线程各自执行完毕后再执行。
        CountDownLatch latch = new CountDownLatch(300);  //构造300的计数器
        //任务
        Runnable task = ()->{
            for(int i=0;i < 100;i++){
                long id =redisIdWorker.nextId("order");
                System.out.println("id = " + id);
            }
            latch.countDown(); //对计数器进行递减1操作,当计数器递减至0时,当前线程会去唤醒阻塞队列里的所有线程。
        };
        long begin = System.currentTimeMillis();
        //300个线程执行任务
        for(int i=0;i < 300;i ++){
            es.submit(task);
        }

        try {
            //等待latch计数器归零再开始执行该线程
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        long end = System.currentTimeMillis();

        System.out.println("time = " + (end-begin) );

    }

After running, an order counter named splicing is written into redis. 

Generated successfully

3. Add coupons

Basically, the front end transmits coupon json data and calls control and service for database processing.

3.1 Table structure

The two tables are linked by coupon id

flash sale coupon

 All coupons (including ordinary coupons and flash sale coupons)

3.2 Add coupons

You can get the information by passing json through post

4. Implement the coupon purchase process

Corresponding coupon purchase service process

5. Solve the problem of multi-threaded flash sales and overselling

5.1 Simulate multi-user request software

The video uses JMeter software to test the load. It can set the number of threads and initiate a large number of requests to a certain URL at the same time to simulate multi-user scenarios.

JMeter performance testing, complete introductory tutorial-CSDN Blog

5.2 Oversold problem

A judgment will be made before selling something, and the function of deducting inventory will be called only after the judgment is successful. If the inventory is 1, and the two threads successfully determine that there is inventory at the same time, and then deduct one inventory respectively, then the inventory is -1 and there is an oversold problem. .

5.3 Solution (locking, optimistic locking, pessimistic locking)

Pessimistic locking is a traditional lock and has a great impact on efficiency, so we study how to implement optimistic locking.

Optimistic locking needs to determine the version number based on modifications, so it can only be applied to updates. For multi-threaded queries, only pessimistic locking can be used.

5.4 Optimistic locking

Optimistic locking needs to determine the version number based on modifications, so it can only be applied to updates. For multi-threaded queries, only pessimistic locking can be used.

5.4.1 Version number method

5.4.2CAS method (use inventory as version number Compare and switch)

5.5 Optimistic lock implementation---CAS method

Before deducting inventory, add an inventory to determine whether it is the same as before.

But this has a new problem: the success rate is too low. If 100 threads operate at the same time, only one thread can be modified, and the others will exit due to version changes, resulting in an increase in the error rate.

Therefore, there is no need to judge whether the inventory is the same as before in the code. As long as the inventory is greater than 0, it can be sold.

5.5 Segment lock

Because optimistic locking will increase the failure rate, in order to increase the success rate, segmented locking can be used to disperse 100 coupons into 10 tables. Users can go to 10 tables to grab them respectively. In this way, one purchase and locking will Only one table needs to be locked, which does not affect the purchase of other tables, greatly improving the success rate.

Guess you like

Origin blog.csdn.net/m0_50973548/article/details/134982825