In recent business development cannot extricate oneself 🤣 addiction, there was a time not updated blog, subsequent blog content field under plans to put some business scenarios, share, or better design ideas for don’t like before around a theme, consumes a lot of time to finish the related content (suppress bigger), follow-up may be a capacity is not so rich, But as far as possible for a point for more detailed, or more in-depth analysis, through continuous sharing and self-review, experience precipitation, while improving the frequency of blog sharing 🤙
scenario
Scenario 1
Message function limit, 30 seconds can only comment 10 times, beyond the number of not allowed to comment again, and prompt: too frequentCopy the code
Scenario 2
The "like" function is limited. It can only be "like" 10 times within 10 seconds. If the number exceeds the limit, no more "like" can be clicked, and the operation is forbidden for 1 hourCopy the code
Scenario 3
Upload record function, limit a day can only upload 100 times, exceed the number can not be uploaded again, and prompt: exceed today onlineCopy the code
Out of nature
In the process of business development, we have been involved in various business scenarios of scheme design, often easy to encounter similar scenes, but the current of business module, in fact, the nature of these requirements is to solve the same problem, when meet this kind of scenario, we need according to oneself experience analysis out of demand the nature of the problem, Implementing a generic solution to make your solution more valuable can be the difference between being a soulful engineer and the best copy paste in the business.
By analyzing the above three business scenarios, we can find that there is similar logic among them, which is called the same problem. Now we are going to separate this problem, design a general solution, and draw the same logic flow chart:
By analyzing the requirements scenario above, isolate what they all need:
- Restricted objects: Users
- Restrict actions (comments, likes, records,…)
- Time range X seconds
- Limit the number of operations to Y
- Operation time Z (seconds/specific time)
- Do not allow operation after exceeding, and prompt
(The minimum time unit is seconds: days/hours/minutes can be converted into seconds, and more scenes can be solved with seconds)
If the function is separated into a general function, it looks something like this:
/** * frequency limit *@paramString $action Action *@paramInt $userId specifies the userId * that initiates the operation@paramInt $time Time range X seconds *@paramInt $number Limits the number of operations to Y *@paramArray $expire beyond seal time Z [' type '= > 1,' TTL = > expiration time/seconds] [' type '= > 2,' TTL = > specific expiration timestamp] a choice *@return bool
* @throws \Exception
*/
public static function frequencyLimit(string $action, int $userId, int $time, int $number, $expire = [])
{
// ToDO performs frequency control and failure release according to the user operation time range
}
Copy the code
Solution landing
In this function, we need to store the operation and time initiated by the user, as well as the total number of times, and also need to clean up the invalid and expired. If we rely on mysql for storage at this time, we feel quite painful. Redis finally appeared. Based on the characteristics of RedIS, incR atomic operation and key expiration mechanism, the efficiency advantage of memory storage, it can be relatively simple, flexible and efficient to complete the purpose.
Here is a simple code to achieve a general function:
/** * frequency limit *@paramString $action Action *@paramInt $userId specifies the userId * that initiates the operation@paramInt $time Time range X seconds *@paramInt $number Limits the number of operations to Y *@paramArray $expire beyond seal time Z [' type '= > 1,' TTL = > expiration time/seconds] [' type '= > 2,' TTL = > specific expiration timestamp] a choice *@return bool
* @throws \Exception
*/
public function frequencyLimit(string $action, int $userId, int $time, int $number, $expire = [])
{
if (empty($action) || $userId <= 0 || $time <= 0 || $number <= 0) {
throw new \Exception('Invalid parameter');
}
$key = 'act:limit:' . $action . ':' . $userId;
$r = RedisClient::connect();
// Get the current count
$current = intval($r->get($key));
if ($current >= $number) return false;
// Accumulate and return the latest value
$current = $r->incr($key);
// Set the effective time of the control operation frequency for the first accumulation
if ($current === 1) $r->expire($key, $time);
// The number of times the limit is exceeded
if ($current <= $number) return true;
$current === $number Determine that the expiration time is reset only once
$type = empty($expire['type'])?0 : intval($expire['type']);
$ttl = empty($expire['ttl'])?0 : intval($expire['ttl']);
if ($current === $number && $ttl > 0 && in_array($type, [1.2]) {if ($type === 1) $r->expire($key, $ttl);
if ($type === 2) $r->expireAt($key, $ttl);
}
return false;
}
/ / scenario 1
/** * Comment restrictions *@param int $userId
* @return bool|string
*/
public function doComment(int $userId)
{
try {
$pass = FrequencyLimit::doHandle('comment', $userId, 30.10);
if(! $pass)return 'Too often';
// Todo comment logic
return true;
} catch (\Exception $e) {
return$e->getMessage(); }}/ / scenario 2
/** ** Limit on likes *@param int $userId
* @return bool|string
*/
public function doLike(int $userId)
{
try {
$pass = FrequencyLimit::doHandle('like', $userId, 10.10['type'= >1.'ttl'= >1 * 60 * 60]);
if(! $pass)return 'Too frequent, banned for 1 hour';
// Todo likes logic
return true;
} catch (\Exception $e) {
return$e->getMessage(); }}/ / scenario 3
/** * Upload restriction *@param int $userId
* @return bool|string
*/
public function doUpload(int $userId)
{
try {
$expire = strtotime(date('Y-m-d', strtotime(+1 . 'days')));
$pass = FrequencyLimit::doHandle('upload', $userId, 1 * 24 * 60 * 60.100['type'= >2.'ttl' => $expire]);
if(! $pass)return 'Beyond online Today';
// todo upload logic
return true;
} catch (\Exception $e) {
return$e->getMessage(); }}//场景N
Copy the code
Coding can be further abstracted depending on the complexity of your design of the general scheme, such as abstraction into frequency-limited function classes
conclusion
- Analyze similar business scenarios to identify underlying problems and design common solutions
- Make the solution more valuable and be a developer with a soul
- Master Redis and make full use of its features and advantages
Posted on Github🌈 Welcome to Star 🥰