In flash sale scenarios where the sales period or product quantity is limited, you must handle traffic peaks that occur before, during, and after the sale period. You must also make sure that the number of purchase orders accepted does not exceed the number of products in stock. To handle these challenges, the TairString data structure of Tair provides a simple and efficient way to implement bounded counters. You can use bounded counters to ensure that the accepted purchase orders do not exceed the upper limit. The solutions described in this topic are also applicable to other scenarios where rate limiting or throttling is required.
Bounded counters for flash sales
The TairString data structure is more powerful than the native Redis String data structure. TairString offers all the features of Redis String except bit operations.
The EXINCRBY and EXINCRBYFLOAT commands for TairStrings have similar functions to the INCRBY and INCRBYFLOAT commands for native Redis strings. You can use these commands to increment or decrement values. The EXINCRBY and EXINCRBYFLOAT commands support more options than the two commands for native Redis strings. These options include EX, NX, VER, MIN, and MAX. For more information, see TairString. The solution described in this topic uses the MIN and MAX options. The following table describes the two options.
Option | Description |
---|---|
MIN | Specifies the minimum TairString value. |
MAX | Specifies the maximum TairString value. |
If you use native Redis strings to handle the challenges of flash sales, the required code is complex and difficult to manage. This may lead to excess purchase orders, where users are able to make successful purchases of items even after these items have already been sold out. TairString allows you to compile and run simple code to limit the exact number of purchase orders. Sample pseudocode:
if(EXINCRBY(key_iphone, -1, MIN:0) == "would overflow")
run_out();
Bounded counters for throttling
As with Bounded counters for flash sales, you can specify the MAX option of the EXINCRBY command to implement bounded counters for throttling. Sample pseudocode:
if(EXINCRBY(rate_limitor, 1, MAX:1000) == "would overflow")
traffic_control();
Bounded counters for throttling can be used for a variety of reasons such as limiting the number of concurrent requests, access frequency, and number of password changes. For example, in concurrency limiting scenarios, the number of concurrent requests suddenly exceeds the system performance threshold. To prevent service failures that cause severe consequences, you can use a bounded counter as a temporary solution to control the number of concurrent requests. This solution can respond to concurrent requests in a timely manner. If you want to limit the number of queries per second (QPS), you can compile and run simple code by using the EXINCRBY command for TairStrings to set a bounded counter for concurrent requests.
/**
* tryAcquire is thread-safe and will increment the key from 0 to the upper bound within an interval of time,
* and return failure once it exceeds
* @param key the key
* @param upperBound the max value
* @param interval the time interval
* @return acquire success: true; fail: false
*/
public static boolean tryAcquire(String key, int upperBound, int interval) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.eval("if redis.call('exists', KEYS[1]) == 1 "
+ "then return redis.call('EXINCRBY', KEYS[1], '1', 'MAX', ARGV[1], 'KEEPTTL') "
+ "else return redis.call('EXSET', KEYS[1], 0, 'EX', ARGV[2]) end",
Arrays.asList(key), Arrays.asList(String.valueOf(upperBound), String.valueOf(interval)));
return true;
} catch (Exception e) {
if (e.getMessage().contains("increment or decrement would overflow")) {
return false;
}
e.printStackTrace();
}
return false;
}