整理自:
https://www.cnblogs.com/itbsl/p/13407489.html
https://www.cnblogs.com/myJuly/p/13608475.html
https://mp.weixin.qq.com/s/JQYWVL2YUKLiVZfV99z4cg
如果有侵权请联系删除
令牌桶算法
-
首先设有一个令牌桶,桶内存放令牌,一开始令牌桶内的令牌是满的(桶内令牌的数量可根据服务器情况设定)
-
每次访问从桶内取走一个令牌,当桶内令牌为0,则不允许再访问。
-
每隔一段时间,放入令牌,最多使桶内令牌满额。
class TrafficShaperController extends Controller { /** * 令牌桶总数量 * @var int */ private $totleNum = 25; /** * 令牌标识(可以根据需要加上关键ID,uid、orderid...) * @var string */ private $quekueName ="TrafficShaper_queue"; /** * redis缓存类 * @var object */ private $redis; /** * 初始化方法 * * @author heyw<1051834593@qq.com> * @since 2020/12/10 */ public function _initialize() { $this->redis = Redis::getInstance(); } /** * 模拟用户消耗令牌 * * @param int $num * @author heyw<1051834593@qq.com> * @since 2020/12/10 */ public function run($num = 1) { // 初始化 $this->reset(); // 模拟1s请求10次 while (1) { $this->getKey(); sleep(0.1); } } /** * 获取令牌 * * @return bool * @author heyw<1051834593@qq.com> * @since 2020/12/11 */ protected function getKey() { // 初始化 $redis = $this->redis; $queueName = $this->quekueName; // 获取一个令牌,如果没有直接返回 $res = $redis->rPop($queueName); // 获得令牌,处理业务 var_dump($res ?'get it' : 'empty'); return true; } /** * 重置 * * @author heyw<1051834593@qq.com> * @since 2020/12/11 */ protected function reset() { $this->redis->delete($this->quekueName); $this->add(25); } /** * 定时加入令牌桶,1s执行1次 * * @author heyw<1051834593@qq.com> * @since 2020/12/10 */ public function add($stepNum = 5) { // 初始化 $redis = $this->redis; $queueName = $this->quekueName; // 当前令牌书 $currNum = $redis->lSize($queueName) ?: 0; $maxNum = $this->totleNum; $addNum = $maxNum >= $currNum + $stepNum ? $stepNum : $maxNum - $currNum; if ($addNum == 0) { return true; } // 加入令牌 $token = array_fill(0, $addNum, 1); $redis->lPush($queueName, $token); return true; } }