当前位置:网站首页>Design a red envelope grabbing system

Design a red envelope grabbing system

2022-07-06 23:34:00 OoZzzy

1. Demand analysis

Common red envelope systems , Amount specified by the user 、 The total number of red packets is used to complete the creation of red packets , Then the red packet is distributed to the target user through a certain portal , After the user sees the red envelope , Click red envelope , Get red packets randomly , Last , Users can view the red packets they have grabbed . The whole business process is not complicated , The difficulty lies in Grab a red envelope This behavior may have High concurrency . therefore , The optimization point of system design mainly focuses on Grab a red envelope In this behavior .

  • Hand out red envelopes : The user sets the total amount of red packets 、 Total quantity
  • Grab a red envelope : The user gets a certain amount randomly from the total red packet

High availability must be ensured for red packets , Otherwise, users will be very angry . secondly , The consistency of system data must be ensured, and no over issuance is allowed , Otherwise, users who get red packets will not receive money , Users will be angry . And finally , The system may have high concurrency .

2. Table structure design

Red envelope activity table

CREATE TABLE `t_redpack_activity`
(
    `id`         bigint(20)     NOT NULL COMMENT ' Primary key ',
    `total_amount`     decimal(10, 2) NOT NULL DEFAULT '0.00' COMMENT ' Total sum ',
    `surplus_amount`     decimal(10, 2) NOT NULL DEFAULT '0.00' COMMENT ' The remaining amount ',
    `total` bigint(20)     NOT NULL DEFAULT '0' COMMENT ' Total number of red packets ',
    `surplus_total` bigint(20)     NOT NULL DEFAULT '0' COMMENT ' Total remaining red packets ',
    `user_id`    bigint(20)     NOT NULL DEFAULT '0' COMMENT ' The user id ',
    `version` bigint(20)     NOT NULL DEFAULT '0' COMMENT ' Version number ',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

Red envelope table

CREATE TABLE `t_redpack`
(
    `id`         bigint(20)     NOT NULL COMMENT ' Primary key ',
    `activity_id`         bigint(20)     NOT NULL DEFAULT 0 COMMENT ' Red envelope activity ID',
    `amount`     decimal(10, 2) NOT NULL DEFAULT '0.00' COMMENT ' amount of money ',
    `status`     TINYINT(4) NOT NULL DEFAULT 0 COMMENT ' Red envelope status  1 You can use  2 Unavailable ',
    `version` bigint(20)     NOT NULL DEFAULT '0' COMMENT ' Version number ',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

A detailed list

CREATE TABLE `t_redpack_detail`
(
    `id`         bigint(20)     NOT NULL COMMENT ' Primary key ',
    `amount`     decimal(10, 2) NOT NULL DEFAULT '0.00' COMMENT ' amount of money ',
    `user_id`    bigint(20)     NOT NULL DEFAULT '0' COMMENT ' The user id ',
    `redpack_id` bigint(20)     NOT NULL DEFAULT '0' COMMENT ' Red envelope number ',
    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ' Creation time ',
    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ' Update time ',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

Activity list , Is how many red envelopes you sent , And the remaining amount needs to be maintained . The schedule is the red packet details that the user grabs . The red packet table is the information of each specific red packet . Why do you need three tables ? In fact, if there is no red envelope table, it is OK . However, our scheme needs to use a table to record the information of red packets in advance , That's why the table was designed .

3. Implementation based on distributed lock

 Insert picture description here
The implementation based on distributed lock is the simplest and crudest , The whole red packet interface is used to activityId As key To lock , Ensure that the same batch of red packet robbing is executed serially . The implementation of distributed locks is implemented by spring-integration-redis The project provides , The core class is RedisLockRegistry. Lock through Redis Of lua Script implementation , And it realizes blocking local reentrant .

4. Implementation based on optimistic lock

 Insert picture description here
The second way , Add optimistic lock version control to the red packet activity table , When multiple threads update the same activity table at the same time , only one clien You will be successful . Other failures client Cycle retry , Set a maximum number of cycles . This scheme can realize the processing in the case of concurrency , But the conflict is great . Because only one person will succeed at a time , other client Need to try again , Even if you try again, only one person can succeed at a time , therefore TPS Very low . When the set number of failed retries is less than the number of red packets issued , It may lead to someone not grabbing the red envelope in the end , In fact, there are still red envelopes left .

5. Implementation based on pessimistic lock

 Insert picture description here
Due to the increase of red packet activity table, optimistic lock conflicts are very large , So consider using pessimistic locks :select * from t_redpack_activity where id = #{id} for update, Note that pessimistic locks must be used in transactions . here , All red packet grabbing becomes serial . In this case , Pessimistic locks are far more efficient than optimistic locks .

6. Pre allocate red packets , Implementation based on optimistic lock

 Insert picture description here

You can see , If we add the dimension of Le Guan lock to the red packet details , Then the conflict will be reduced . Because the red packet details were created after the user grabbed them , Now you need to pre allocate red packets , That is, when you create a red packet activity, you will generate N Red envelopes , Control availability through status / Unavailable . such , When more than one client When you grab a red envelope , Get all available red packet details under this activity , Randomly return one of them and then update it , The successful update means that the user has grabbed the red packet , Failure is a sign of conflict , You can cycle through retry . such , Conflict is reduced .

7. be based on Redis Implementation of queues

 Insert picture description here
Similar to the previous scheme , however , A corresponding number of red envelopes will be created when users issue red envelopes , And join in Redis In line . When grabbing a red envelope, it will pop up .Redis The queue fits our needs very well , There will be no duplicate elements in each pop-up , Destroy when used up . defects : When grabbing a red envelope, once it pops out of the queue , At this point the system crashes , After recovery, the details of red packets in this queue have been lost , Manual compensation is required .

8. be based on Redis queue , Asynchronous storage

 Insert picture description here
In this scheme, you do not operate the database after you get the red packet , Instead, it saves persistent information to Redis in , Then return to success . Through another thread UserRedpackPersistConsumer, Pull the persistent information for warehousing . It should be noted that , In this case, if you use the normal pop There will still be crash point The problem of , So considering availability , Use here Redis Of BRPOPLPUSH operation , Pop up the element and add it to the backup queue , Ensure that the crash here can be automatically recovered through the backup queue . Crash recovery thread CrashRecoveryThread Pull backup information regularly , Go to DB Verify whether the persistence is successful , If successful, clear this element , Otherwise, compensate and clear this element . If an exception occurs during the operation of the database, the error log will be recorded redpack.persist.log, This log uses a separate file and format , Easy to compensate ( Generally not triggered ).

Redis High availability is required .

原网站

版权声明
本文为[OoZzzy]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207061551333674.html