PHP에서 토큰 버킷 현재 제한을 구현하는 방법: 1. 토큰 버킷을 설정하고 버킷에 토큰을 저장합니다. 2. 방문할 때마다 버킷에서 하나의 토큰을 가져옵니다. 3. 실제 상황에 따라 매 기간마다 다음을 수행할 수 있습니다. 언제든지 몇 개의 토큰을 넣거나 토큰 버킷을 직접 채울 수 있습니다.
이 문서의 운영 환경: Windows 7 시스템, PHP7.1, Dell G3 컴퓨터.
PHP는 토큰 버킷 현재 제한을 어떻게 구현하나요?
php는 토큰 버킷 알고리즘을 사용하여 redis 기반 트래픽 제어를 달성합니다
이 글에서는 Redis 기반 PHP를 소개하고 토큰 버킷 알고리즘을 사용하여 액세스 트래픽을 제어하며 완전한 알고리즘 설명을 제공합니다. 누구나 쉽게 배우고 사용할 수 있는 데모 예제입니다.
국내 명절이나 중요한 축제가 있을 때마다 국내 명승지나 지하철은 사람들로 붐비기 때문에 일부 지역에서는 입장 인원을 제한하는 흐름 제한 조치를 취합니다. 특정 값으로 감소하면 입장이 허용됩니다.
예:
해당 지역에 허용되는 최대 인원은 M
현재 해당 지역의 인원 수는 N
사람이 들어올 때마다 N+1, N일 때 = M, 입장 불가
사람이 나갈 때마다 N-1, N < 서버에 대한 압력이 순간적으로 급증하여 시스템에 과부하가 걸립니다.
을 사용하여 비즈니스 유형에 따른 서버 부담을 줄일 수 있습니다. 명승지의 교통 제한과 다르게, 방문부터 시스템 종료까지의 시간이 매우 짧기 때문에
각 방문의 평균 지속 시간만 알고 최대 동시 방문자 수를 설정하면 됩니다.토큰 버킷 알고리즘
redis
의 큐를 사용할 수 있으며,lPush(enqueue), rPop(dequeue)을 사용할 수 있습니다. , 토큰 추가 및 소비 작업을 구현합니다.
TrafficShaper.class.php<?php
/**
* PHP基于Redis使用令牌桶算法实现流量控制
* Date: 2018-02-23
* Author: fdipzone
* Version: 1.0
*
* Descripton:
* php基于Redis使用令牌桶算法实现流量控制,使用redis的队列作为令牌桶容器,入队(lPush)出队(rPop)作为令牌的加入与消耗操作。
*
* Func:
* public add 加入令牌
* public get 获取令牌
* public reset 重设令牌桶
* private connect 创建redis连接
*/class TrafficShaper{ // class start
private $_config; // redis设定
private $_redis; // redis对象
private $_queue; // 令牌桶
private $_max; // 最大令牌数
/**
* 初始化
* @param Array $config redis连接设定
*/
public function __construct($config, $queue, $max){
$this->_config = $config; $this->_queue = $queue; $this->_max = $max; $this->_redis = $this->connect();
} /**
* 加入令牌
* @param Int $num 加入的令牌数量
* @return Int 加入的数量
*/
public function add($num=0){
// 当前剩余令牌数
$curnum = intval($this->_redis->lSize($this->_queue)); // 最大令牌数
$maxnum = intval($this->_max); // 计算最大可加入的令牌数量,不能超过最大令牌数
$num = $maxnum>=$curnum+$num? $num : $maxnum-$curnum; // 加入令牌
if($num>0){ $token = array_fill(0, $num, 1); $this->_redis->lPush($this->_queue, ...$token); return $num;
} return 0;
} /**
* 获取令牌
* @return Boolean
*/
public function get(){
return $this->_redis->rPop($this->_queue)? true : false;
} /**
* 重设令牌桶,填满令牌
*/
public function reset(){
$this->_redis->delete($this->_queue); $this->add($this->_max);
} /**
* 创建redis连接
* @return Link
*/
private function connect(){
try{ $redis = new Redis(); $redis->connect($this->_config['host'],$this->_config['port'],$this->_config['timeout'],$this->_config['reserved'],$this->_config['retry_interval']); if(empty($this->_config['auth'])){ $redis->auth($this->_config['auth']);
} $redis->select($this->_config['index']);
}catch(RedisException $e){ throw new Exception($e->getMessage()); return false;
} return $redis;
}
} // class end?>
<?php
/**
* 演示令牌加入与消耗
*/
require 'TrafficShaper.class.php';
// redis连接设定
$config = array(
'host' => 'localhost',
'port' => 6379,
'index' => 0,
'auth' => '',
'timeout' => 1,
'reserved' => NULL,
'retry_interval' => 100,
);
// 令牌桶容器
$queue = 'mycontainer';
// 最大令牌数
$max = 5;
// 创建TrafficShaper对象
$oTrafficShaper = new TrafficShaper($config, $queue, $max);
// 重设令牌桶,填满令牌
$oTrafficShaper->reset();
// 循环获取令牌,令牌桶内只有5个令牌,因此最后3次获取失败
for($i=0; $i<8; $i++){
var_dump($oTrafficShaper->get());
}
// 加入10个令牌,最大令牌为5,因此只能加入5个
$add_num = $oTrafficShaper->add(10);
var_dump($add_num);
// 循环获取令牌,令牌桶内只有5个令牌,因此最后1次获取失败
for($i=0; $i<6; $i++){
var_dump($oTrafficShaper->get());
}
?>
출력:
boolean true boolean true boolean true boolean true boolean true boolean false boolean false boolean false int 5 boolean true boolean true boolean true boolean true boolean true boolean false정기적으로 가입하는 토큰 알고리즘정기적으로 가입하는 토큰을 사용할 수 있습니다. crontab 달성, 매분 여러 토큰을 추가하는 add 메소드입니다. crontab의 최소 실행 간격은 1분입니다. 토큰 버킷에 있는 토큰이 처음 몇 초 동안 소모되면 남은 수십 초 동안 토큰을 얻지 못해 사용자를 기다리는 시간이 발생합니다. 더 길게. 우리는 토큰 추가 알고리즘을 최적화하고 1분 내에 몇 초마다 여러 토큰을 추가할 수 있습니다. 이를 통해 1분 내에 매번 토큰을 얻을 수 있는 기회가 보장됩니다.
crontab에서 호출하는 토큰 추가 프로그램은 다음과 같으며 초당 3개의 토큰을 자동으로 추가합니다.
<?php /** * 定时任务加入令牌 */ require 'TrafficShaper.class.php'; // redis连接设定 $config = array( 'host' => 'localhost', 'port' => 6379, 'index' => 0, 'auth' => '', 'timeout' => 1, 'reserved' => NULL, 'retry_interval' => 100, ); // 令牌桶容器 $queue = 'mycontainer'; // 最大令牌数 $max = 10; // 每次时间间隔加入的令牌数 $token_num = 3; // 时间间隔,最好是能被60整除的数,保证覆盖每一分钟内所有的时间 $time_step = 1; // 执行次数 $exec_num = (int)(60/$time_step); // 创建TrafficShaper对象 $oTrafficShaper = new TrafficShaper($config, $queue, $max); for($i=0; $i<$exec_num; $i++){ $add_num = $oTrafficShaper->add($token_num); echo '['.date('Y-m-d H:i:s').'] add token num:'.$add_num.PHP_EOL; sleep($time_step); } ?>시뮬레이션 소비 프로그램은 다음과 같으며, 초당 2~8개의 토큰을 소비합니다.
<?php /** * 模拟用户访问消耗令牌,每段时间间隔消耗若干令牌 */ require 'TrafficShaper.class.php'; // redis连接设定 $config = array( 'host' => 'localhost', 'port' => 6379, 'index' => 0, 'auth' => '', 'timeout' => 1, 'reserved' => NULL, 'retry_interval' => 100, ); // 令牌桶容器 $queue = 'mycontainer'; // 最大令牌数 $max = 10; // 每次时间间隔随机消耗的令牌数量范围 $consume_token_range = array(2, 8); // 时间间隔 $time_step = 1; // 创建TrafficShaper对象 $oTrafficShaper = new TrafficShaper($config, $queue, $max); // 重设令牌桶,填满令牌 $oTrafficShaper->reset(); // 执行令牌消耗 while(true){ $consume_num = mt_rand($consume_token_range[0], $consume_token_range[1]); for($i=0; $i<$consume_num; $i++){ $status = $oTrafficShaper->get(); echo '['.date('Y-m-d H:i:s').'] consume token:'.($status? 'true' : 'false').PHP_EOL; } sleep($time_step); } ?>Demonstration
예약된 작업을 설정하고 1분에 한 번씩 실행
* * * * * php /程序的路径/cron_add.php >> /tmp/cron_add.log실행 시뮬레이션 소비
php consume_demo.php실행 결과:
[2018-02-23 11:42:57] consume token:true [2018-02-23 11:42:57] consume token:true [2018-02-23 11:42:57] consume token:true [2018-02-23 11:42:57] consume token:true [2018-02-23 11:42:57] consume token:true [2018-02-23 11:42:57] consume token:true [2018-02-23 11:42:57] consume token:true [2018-02-23 11:42:58] consume token:true [2018-02-23 11:42:58] consume token:true [2018-02-23 11:42:58] consume token:true [2018-02-23 11:42:58] consume token:true [2018-02-23 11:42:58] consume token:true [2018-02-23 11:42:58] consume token:true [2018-02-23 11:42:58] consume token:false [2018-02-23 11:42:59] consume token:true [2018-02-23 11:42:59] consume token:true [2018-02-23 11:42:59] consume token:true [2018-02-23 11:42:59] consume token:false [2018-02-23 11:42:59] consume token:false [2018-02-23 11:42:59] consume token:false [2018-02-23 11:42:59] consume token:false [2018-02-23 11:43:00] consume token:true [2018-02-23 11:43:00] consume token:true [2018-02-23 11:43:00] consume token:true [2018-02-23 11:43:00] consume token:false [2018-02-23 11:43:00] consume token:false처음에 토큰 버킷이 가득 차 있기 때문입니다(최대 토큰 수 10개). 이므로 최초 10회부터 토큰을 획득할 수 있으며, 10회 이후에는 소모된 토큰이 추가된 토큰 수보다 많은 경우에 따라 접근이 제한됩니다.
추천 학습: "
PHP 비디오 튜토리얼
위 내용은 PHP에서 토큰 버킷 현재 제한을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!