I. Scenario analysis

Wechat snatching red envelopes has been a very common scene in our life, especially at the end of the company’s annual meeting and the Spring Festival two periods, the elder leaders are giving red envelopes, hand cramps, but did not grab much.

During this period of time, for a single red envelope in a single group, QPS is also thousands, for the whole wechat red envelope system, the peak concurrency is hundreds of millions.

Gao Feng snatching red envelopes has three characteristics:

  1. There are many people who pack red envelopes: that is, the task of creating a red envelope is more, that is, the red envelope system is distinguished by the task of a single red envelope, which is characterized by more tasks in the peak period.
  2. More people grab red envelopes: When you send out the red envelope, there are dozens or even hundreds of people to grab your red envelope, that is, the number of requests for a single red envelope is large.
  3. Low latency: When you find a red envelope, the faster you grab the red envelope, the happier you will be. Therefore, the response speed of grabbing a red envelope should be fast, usually 1 second.

Ii. Technical scheme

  1. Pack a red envelope
  • The amount firstdismantlingFor a small amount of red envelope, for example, a total amount of 1000 yuan, send 10 red envelopes, users click save, it will be automatically divided into 10randomSmall red envelopes.
    • Storage is a problem here. How to store multiple amounts (e.g., 10 red packets of small amounts)?

  1. Grab a red envelope
  • The key technology at the core of high-concurrency red envelope snatching is to control the operation of each small red envelopeatomic.
    • For example, 10 red packets are robbed in a group of 100 people. If one of the 10 red packets is robbed, the inventory of the red packets should be reduced by 1, that is, the remaining 19 red packets. The whole process of snatching one and red envelope inventory minus 1 is an atomic operation.
  • The list ofpopAn operation that pops an element automatically removes that element from the queue. It is aAtomic operation.

Three, case actual combat

Pack a red envelope

    /** ** /
    @GetMapping(value = "/set")
    public long setRedpacket(int total, int count) {
        // Unpack the red envelope
        Integer[] packet= this.splitRedPacket(total,count);
        // Generate globally unique IDS for red packets
        long n=this.incrementId();
        // Use list to store red packets
        String key=RED_PACKET_KEY+n;
        this.redisTemplate.opsForList().leftPushAll(key,packet);
        // Set expiration to 3 days
        this.redisTemplate.expire(key,3, TimeUnit.DAYS);
        log.info("Unpack the red envelope {}={}",key,packet);
        return n;
    }
Copy the code

Disassemble a red envelope

/** * Unpack the red envelope * 1. The amount of the red envelope should be unpacked * 2. The amount of red packets should not be too different * total amount * count Number of red packets */
public  Integer[] splitRedPacket(int total, int count) {
    int use = 0;
    Integer[] array = new Integer[count];
    Random random = new Random();
    for (int i = 0; i < count; i++) {
        if (i == count - 1)
            array[i] = total - use;
        else {
            // Red envelope random amount floating coefficient
            int avg = (total - use) * 2 / (count - i);
            array[i] = 1 + random.nextInt(avg - 1);
        }
        use = use + array[i];
    }
    return array;
}
Copy the code

Grab a red envelope

    
    /** ** /
    @GetMapping(value = "/rob")
    public int rob(long redid,long userid) {
        // Step 1: Verify that the user is robbed
        Object packet=this.redisTemplate.opsForHash().get(RED_PACKET_CONSUME_KEY+redid,String.valueOf(userid));
        if(packet==null) {// Step 2: From the list queue, pop a red envelope
            Object obj=this.redisTemplate.opsForList().leftPop(RED_PACKET_KEY+redid);
            if(obj! =null) {// Step 3: Grab the red envelope and save it
                this.redisTemplate.opsForHash().put(RED_PACKET_CONSUME_KEY+redid,String.valueOf(userid),obj);
                log.info("User ={} grab {}",userid,obj);
                //TODO asynchronously drops data to the database
                
                return (Integer) obj;
            }
            //-1 indicates that the robbery is complete
            return -1;
        }
        //-2 means robbed
        return -2;
    }

Copy the code

Redis distributed cache series

Redis Distributed Cache (28) – Cache breakdown Solutions

  • 👍🏻 : have harvest, praise encouragement!
  • ❤️ : Collect articles, easy to look back!
  • 💬 : Comment exchange, mutual progress!