Dark Horse Review 09 Flash Sale Function Summary

 1. Overall business process

1.1 redis judgment process (single thread)

1. First obtain the order id and user id, and call the Lua script to perform redis operations. Lua includes judging purchase qualifications/inventory adequacy, deducting inventory and placing orders, and sending order messages to Stream.

2. Stream forms a message queue, and any exceptions are automatically placed in the pending-list.

1.2 Thread process (multiple threads take turns)

1. The thread reads the message queue (read message queue). If it can read the message, continue reading; if it reads the order message, it parses the message content, calls order function 3 to write to the database, and then replies with a confirmation ack; if If an exception occurs, go to step 2 of penging-list.

2. Process the penging-list, parse the message, place an order, and process; if there is an exception, repeat the cycle and continue processing; until the processing is completed, the process will exit.

3. Add Redisson distributed lock and call the create order database operation.

2. What problems were solved?

2.1. Oversold problem --> optimistic lock

Through optimistic locking, the inventory is used as the version number. As long as the inventory is greater than 0, orders can be allowed (there will be measures to solve it later)

Code in lua script

2.2 One person, one order -> maintain set, store user id + coupon id, judge heavy

sismember to determine whether the records of user id and coupon id exist in the collection at the same time

The set structure ensures that even if there are a large number of users, the number of duplications can be minimized, and the existence judgment efficiency is also high.

2.3 Avoid frequent reading of Lua scripts

Defined as a static resource, it can be accessed at any time without having to read the Lua script repeatedly.

2.3 Why distributed lock Redisson

Distributed locks can ensure the uniqueness of locks on different server JVMs in cluster mode.

Subsequently, Redisson used a hash structure because it can ensure reentrancy.

Redisson automatically solves the problems of 2.4 and 2.5 internally.

2.4 (This problem only occurs with self-implementation) Distributed lock crash deadlock --> Set expiration time + ensure atomicity lua script

The expiration time ensures that the lock will expire and be released after the service goes down.

The Lua script guarantees that the lock will not crash before the expiration time is added.

Redisson automatically implements the atomic operation of expiration time and locking (lua) internally, so it will not be executed separately and will not deadlock.

2.5 (This problem only occurs with self-implementation) Multi-threaded accidental deletion of distributed locks --> Determine thread identification + ensure atomicity Lua script

Determine the unique thread ID of the lock. If it is not your own, do not delete it.

Lua ensures atomicity and avoids the gap between ID judgment and lock deletion.

Redisson has a watchdog mechanism that automatically renews the lock, so there is no problem of lock expiration causing other threads to acquire the lock and delete it accidentally . Only after the service goes down and the watchdog mechanism stops will the lock expire, but this is not a problem of accidental deletion (the service is blocked but not down).

 2.6 Redisson can re-enter, retry, and automatically renew

Reentrant: The bottom layer of the lock is a hash structure, the name of the hash is, the key (field) of the hash is the thread name, and the value is the number of reentrants.

The number of times to acquire the lock is increased by one, and the number of times to complete the lock is reduced by one. Only when the number of times is 0, the thread will release the lock.

Retryable: publish subscription. Subscribe to the lock message. Once other threads release the lock, a message will be published to notify others to grab it. There is a remaining retry time waitTime. If the sum of all lock grabbing times exceeds this threshold, the retry will be given up. If there is still remaining retry time, continue to wait for the release and then grab it. The time waiting for the release is the current remaining retry time. . If you can't wait, don't wait.

 Automatic renewal: watchdog, a function to reset the retry time (default 30s), starting from 30s each time. Then recurse to achieve wireless renewal.

3. Some data structures

3.1 in redis

3.1.1 Set for one person and one order

Use the set structure of redis, including order id and user id

redis.call('sismember', orderKey, userId) == 1)

3.1.2 Message Queue Stream

--3.5 Send messages to redis stream queue, xadd stream.orders * k1 v1 k2 v2... 
redis.call('xadd', 'stream.orders', '*', 'userId', userId, ' voucherId', voucherId, 'id', orderId)

3.1.3 Stock counting using String

redis.call('get', stockKey)) <= 0)

3.2 in mysql

3.2.1 Complete Order

Persisting incoming orders

3.2.2 Coupons and flash sale coupons

Coupon data

4. What can be improved (personal ideas)

4.1 The current project uses a single point redis. In order to improve the concurrency of redis, we will consider introducing the redis cluster strategy later.

4.2 Currently, the message queue uses the Stream type of redis. If you want to improve the robustness of the project, you can switch to professional MQ in the future.

5. Service cluster

Use the function that comes with idea to start multiple simulated clusters of the project, and use nginx to be responsible for reverse proxy and load balancing.

nginx will reverse proxy to multiple nodes you start.

Guess you like

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