トークン バケットの電流制限を実装する PHP メソッド: 1. トークン バケットを設定し、そのバケットにトークンを保存します; 2. 訪問ごとにバケットからトークンを取得します; 3. 実際の状況に従って、時々いくつかのトークンを入れるか、トークンバケットを直接満たしてください。
#この記事の動作環境: Windows7 システム、PHP7.1、Dell G3 コンピューター。
PHP はトークン バケットの電流制限をどのように実装しますか?
##php はトークン バケット アルゴリズムを使用して、redis に基づいたフロー制御を実装します
国内の長期休暇や重要な祭りがある場合、国内の景勝地や地下鉄は人で混雑し、過剰な負荷が発生し、入場者数を制限する流量制限措置が講じられる場合があります。エリア内の人数を一定値まで減らしてから入場を許可します。例:
エリア内で許可される最大人数は MM
エリア内の現在の人数は ですN
すべてのエントリ N = M の場合、1 人
N 1 はエントリできません 人が退出するたびに、N -1、
の場合 N もちろん、プレッシャーを共有するためにサーバーを追加することもできます。まず、サーバーの追加には構成にも一定の時間がかかります。また、特定のアクティビティのためにサーバーが追加された場合、これらのサーバー リソースは無駄になります。活動が終わった後。 したがって、最初に
current Limiting
を使用して、ビジネスの種類に応じてサーバーの負荷を軽減できます。
景勝地の交通制限とは異なり、訪問からシステムの終了までの時間は非常に短いため、各訪問の平均時間を把握し、最大時間を設定するだけで済みます。同時訪問者数です。 トークン バケット アルゴリズム
1. まず、トークン バケットがあり、トークンはそのバケットに格納されます。最初は、トークン バケット内のトークンはいっぱいです (バケット(サーバーの状況に応じてトークンの数を設定できます)。 2. 各訪問はバケットからトークンを取得します。バケット内のトークンが 0 の場合、それ以上の訪問は許可されません。
redis
のキューをトークン バケット コンテナーとして使用できます。lPush (エンキュー)、rPop (デキュー)
を使用して、トークンの追加および消費操作を実装します。
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 の最小実行間隔は 1 分です。最初の数秒でトークン バケット内のトークンが消費されると、残りの数十秒でトークンが取得されなくなります。これにより、ユーザーはもっと待ってください。
トークンを追加するアルゴリズムを最適化し、1 分以内に数秒ごとに複数のトークンを追加することで、1 分以内に毎回トークンを取得できるようにすることができます。crontab によって呼び出されるトークン結合プログラムは次のとおりで、1 秒あたり 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); } ?>
シミュレーション消費プログラムは次のとおりで、1 秒あたり 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); } ?>デモ
スケジュールされたタスクを設定し、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 中国語 Web サイトの他の関連記事を参照してください。