public function checkLimit($cacheKey = '', $initNum = '', $expire = '', $retry = true)
{
$nowTime = time();
Redis::watch($cacheKey);
$redisData = Redis::get($cacheKey);
$limitData = $redisData ? json_decode($redisData, true) : ['num' => $initNum, 'time' => $nowTime];
// (单位时间访问频率 / 单位时间)*(当前时间 - 上次访问时间) = 上次请求至今可增加的访问次数
$addNum = intval(($initNum / $expire) * ($nowTime - $limitData['time']));
$newNum = min($initNum, (($limitData['num'] - 1) + $addNum));
Log::debug($cacheKey . '-剩余领牌次数:' . $newNum);
if ($newNum <= 0) {
return ['status' => false, 'msg' => '当前时刻令牌用完啦!'];
}
$limitData = json_encode(['num' => $newNum, 'time' => $nowTime]);
Redis::multi();
Redis::set($cacheKey, $limitData);
if (!Redis::exec()) {
if (!$retry) {
return ['status' => false, 'msg' => '访问频次过多!'];
} else {
//执行3次丢弃
for ($i = 0; $i < 3; $i++) {
$aRet = self::_limit($cacheKey, $initNum, $expire, false);
if (Arr::get($aRet, 'status', false)) {
break;
}
if (Arr::get($aRet, 'msg') == '当前时刻令牌用完啦') {
return $aRet;
}
}
}
}
return ['status' => true, 'msg' => 'ok'];
}