There are two phase when a user want to buy an item X.
- Checking phase : Checking if item X is available.
- Selling phase: If there is available item X, you will sell it to user and decrease amount of available X.
For example, you have 5 item X. There are 10 users buy item X at same time. 10 orders happen at same time. What if they all are at checking phase? Your system will accept 10 order while you just have 5 item. So how you solve it? This post will give a solution for this by using redis transaction.
To know more about redis transaction, you can read it here:
https://redis.io/topics/transactions
If you just need to execute a sequence commands without checking logic between commands, you can use MULTI - EXEC. But in this case, we need to check the logic if item X is available before deciding to sell it, so we need to use an other option: WATCH.
I will use GO language to show how we deal with it.
Item's status will be save in redis with two key
- Quantity: Amount of item available in ware house.
- Reserved: Amount of success order(but it haven't delivery to user yet)
WATCH
ed keys are monitored in order to detect changes against them. If at least one watched key is modified before the EXEC command, the whole transaction aborts, and EXEC returns a Null reply to notify that the transaction failedWhen the transaction failed, we will recall the function that process order until there is no conflicted transaction.
func reserve(key string) error { err := client.Watch(func(tx *redis.Tx) error { curQuantity, _ := tx.Get(keyQuantity).Int64() curReserved, _ := tx.Get(keyReserved).Int64() if((curQuantity - curReserved) > 1){ _, err = tx.Pipelined(func(pipe *redis.Pipeline) error { pipe.Inc(key) return nil }) } return err }, keyQuantity, keyReserved) if err == redis.TxFailedErr { return reserve(key) } return err }
Không có nhận xét nào:
Đăng nhận xét