The flash sales strategy is commonly used for promotion activities and brand marketing in the e-commerce industry. This strategy can help you increase the number of unique visitors and customer loyalty of your platform. An excellent business system can improve the stability of your platform and ensure the fairness of flash sales. This improves user experience and the reputation of your platform, and maximizes the benefits of flash sales. This topic describes how to use the caching feature of ApsaraDB for Redis to build a highly concurrent business system for handling flash sales.

Characteristics of flash sales

A flash sales activity is intended to sell scarce or special commodities for specified quantities in a timed manner, and attract a large number of buyers. However, only a few buyers place orders during the promotion. A flash sales activity brings visits and order requests dozens or hundreds of times that in regular sales activities on your platform within a short time period.

A flash sales activity is divided into three phases:

  • Before the promotion: Buyers keep refreshing the commodity details page. As a result, the number of requests for this page instantaneously spikes.
  • During the promotion: Buyers place orders. The number of order requests reaches the instantaneous peak.
  • After the promotion: Some buyers that have successfully placed orders keep querying order status or cancel orders. Most buyers keep refreshing the commodity details page and wait for opportunities to place orders after other buyers cancel their orders.

In most cases, a database uses row-level locking to handle requests submitted by buyers. The database allows only requests that hold the lock to query inventory data and place orders. However, the database is incapable of handling high concurrency in this case. The service may be blocked by a large number of requests, which is considered a server crash to the buyers.

Business system for handling flash sales

During a flash sales activity, the business system may receive a large amount of user traffic. However, only a few of the requests are valid. Based on the hierarchy of the system architecture, you can identify and block invalid requests in advance in each phase.

Use the browser cache and Content Delivery Network (CDN) to process user traffic that request static content

Before a flash sales activity, buyers keep refreshing the commodity details page. As a result, the number of requests for this page instantaneously spikes. To resolve this issue, you must present details about commodities for flash sales and details about regular commodities on different web pages. Use static elements to present details about commodities for flash sales. Static data can be cached in the browser and on CDN, except for the place order function that requires interaction between the browser and server. In this way, only a small fraction of the traffic incurred by refreshing the page before the promotion flows to the server.

Use a read/write splitting instance of ApsaraDB for Redis to cache content and block invalid requests

CDN is used to filter and block user traffic in phase 1. In phase 2, you can use a read/write splitting instance of ApsaraDB for Redis to block invalid requests. In phase 2, the business system is responsible for retrieving data. The read/write splitting instance is capable of handling more than 600,000 queries per second, which completely meets the business demands.

Use the data control module to cache the data of commodities for flash sales to the read/write splitting instance, and specify the flag that indicates the promotion activity begins:

"goodsId_count": 100 //The total number of commodities.
"goodsId_start": 0   //The flag that indicates the promotion activity begins.
"goodsId_access": 0  //The number of order requests that have been accepted.
  1. Before the promotion activity begins, the value of the goodsId_Start flag retrieved by the server cluster is 0, which indicates that the promotion activity has not started.
  2. After the data control module changes the value of the goodsId_start flag to 1, the promotion activity begins.
  3. The server cluster then caches the goodsId_start flag and accepts order requests. The cluster updates the number of accepted order requests in goodsId_access. The number of remaining commodities is calculated as follows: goodsId_count - goodsId_access.
  4. After the number of placed orders reaches the value of goodsId_count, the business system blocks subsequent order requests. The number of remaining commodities is set to 0.

In this way, the business system accepts only a small fraction of the order requests. In case of high concurrency, it is acceptable that more traffic may flow to the system. Therefore, you can control the percentage of order requests that the system accepts.

Use a master-replica instance of ApsaraDB for Redis to cache inventory data and accelerate inventory deduction

After the business system receives an order request, the system checks the order information and deducts the inventory. To avoid retrieving data directly from the backend database, you can use a master-replica instance of ApsaraDB for Redis to deduct the inventory. The master-replica instance supports more than 100,000 QPS. ApsaraDB for Redis can help you optimize inventory query, block invalid order requests, and increase the overall throughput of the business system for handling flash sales.

You can use the data control module to cache the inventory data to the ApsaraDB for Redis instance before the promotion activity begins. The instance stores the commodity data for promotion in a hash table.

"goodsId" : {
    "Total": 100
    "Booked": 100
}

To deduct the inventory, the server runs the following Lua script and connects to the ApsaraDB for Redis instance to obtain the permission on placing orders. Lua ensures the atomicity across multiple commands because Redis is a single-thread model.

local n = tonumber(ARGV[1])
if not n  or n == 0 then
    return 0       
end                
local vals = redis.call("HMGET", KEYS[1], "Total", "Booked");
local total = tonumber(vals[1])
local blocked = tonumber(vals[2])
if not total or not blocked then
    return 0       
end                
if blocked + n <= total then
    redis.call("HINCRBY", KEYS[1], "Booked", n)                                   
    return n;   
end                
return 0

Run the SCRIPT LOAD command to cache the Lua script to the ApsaraDB for Redis instance in advance, and then run the EVALSHA command to execute the script. This method requires less network bandwidth than directly running the EVAL command.

redis 127.0.0.1:6379>SCRIPT LOAD "lua code"
"438dd755f3fe0d32771753eb57f075b18fed7716"
redis 127.0.0.1:6379>EVAL 438dd755f3fe0d32771753eb57f075b18fed7716 1 goodsId 1 

If the ApsaraDB for Redis instance returns the value n as the number of commodities that buyers have ordered, the flash sales system determines that the current inventory deduction is successful.

Use a master-replica instance of ApsaraDB for Redis to asynchronously write order data to the database based on message queues

The flash sales business system writes order data to the database after successful inventory deduction. For a few commodities, the system can directly perform operations in the database. If the number of commodities for promotion is more than 10,000 or 100,000, lock conflicts may occur and cause performance bottlenecks in the database. Therefore, to avoid direct operations in the database, the flash sales system writes order data to message queues to complete the order process.

  1. The ApsaraDB for Redis instance provides message queues in a list structure.
     orderList {
         [0] = {Order content} 
         [1] = {Order content}
         [2] = {Order content}
         ...
     }
  2. The flash sales business system writes order content to the ApsaraDB for Redis instance.
    LPUSH orderList {Order content}
  3. The asynchronous order module sequentially retrieves order data from the ApsaraDB for Redis instance and writes order data to the database.
     BRPOP orderList 0

The ApsaraDB for Redis instance provides message queues and asynchronously writes order data to the database to complete the order process.

The data control module manages synchronization of promotion data

At the start, the flash sales business system uses the read/write splitting instance of ApsaraDB for Redis to block invalid traffic and allows a fraction of valid traffic to continue the order process. Afterward, the flash sales business system has to process more traffic caused by order authentication failures and returning orders. Therefore, the data control module regularly computes data in the database, and synchronizes the data to the master-replica instance and then to the read/write splitting instance.