ホームページ  >  記事  >  バックエンド開発  >  Redis に基づくトラフィック制御を実装するためにトークン バケット アルゴリズムを使用して PHP の関連コンテンツを説明する

Redis に基づくトラフィック制御を実装するためにトークン バケット アルゴリズムを使用して PHP の関連コンテンツを説明する

jacklove
jackloveオリジナル
2018-06-08 15:34:221862ブラウズ

この記事では、redis に基づく PHP を紹介し、トークン バケット アルゴリズムを使用してアクセス トラフィックを制御します。誰でも学習して使用できる、アルゴリズムの完全な説明とデモンストレーションの例を提供します。

国内の長期休暇や重要な祭りがある場合、国内の景勝地や地下鉄は混雑し、混雑が予想され、場合によっては交通規制が行われ、乗車数が制限されます。エリア内の人数が減少すると、一定値に達すると入場が許可されます。

例:

エリア内で許可される最大人数は MM
エリア内の現在の人数はN
人が入場するたびに、N 1N = Mの場合、入場は許可されません
人が退出するたびに、N-1N
もちろん、サーバーを追加して圧力を分散することもできます。まず、サーバーの追加には構成にもある程度の時間がかかります。また、特定のアクティビティのためにサーバーが追加された場合、これらのサーバー リソースが無駄になります。活動が終わった後。

したがって、最初に

current Limiting を使用して、ビジネスの種類に応じてサーバーの負荷を軽減できます。 景勝地の交通制限とは異なり、

訪問からシステムの終了までの時間は非常に短いため、各訪問の平均時間を把握し、最大時間を設定するだけで済みます。同時訪問者数。

トークンバケットアルゴリズム
1. まず、トークンバケットがあり、トークンはバケットに格納されます。最初は、トークンバケット内のトークンはいっぱいです(トークンの数)。バケット内の数量はサーバーの状況に応じて設定できます)。

2. 各訪問はバケットからトークンを取得します。バケット内のトークンが 0 の場合、それ以上の訪問は許可されません。

3. 時々、バケットがトークンでいっぱいになるまでトークンを追加します。 (実際の状況に応じて、間隔をあけて複数のトークンを投入することも、トークン バケットを直接埋めることもできます)

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[&#39;host&#39;],$this->_config[&#39;port&#39;],$this->_config[&#39;timeout&#39;],$this->_config[&#39;reserved&#39;],$this->_config[&#39;retry_interval&#39;]);            if(empty($this->_config[&#39;auth&#39;])){                $redis->auth($this->_config[&#39;auth&#39;]);
            }            $redis->select($this->_config[&#39;index&#39;]);
        }catch(RedisException $e){            throw new Exception($e->getMessage());            return false;
        }        return $redis;
    }


} // class end?>

デモ:

<?php/**
 * 演示令牌加入与消耗
 */require &#39;TrafficShaper.class.php&#39;;// redis连接设定$config = array(    &#39;host&#39; => &#39;localhost&#39;,    &#39;port&#39; => 6379,    &#39;index&#39; => 0,    &#39;auth&#39; => &#39;&#39;,    &#39;timeout&#39; => 1,    &#39;reserved&#39; => NULL,    &#39;retry_interval&#39; => 100,
);// 令牌桶容器$queue = &#39;mycontainer&#39;;// 最大令牌数$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 trueboolean trueboolean trueboolean trueboolean trueboolean falseboolean falseboolean falseint 5boolean trueboolean trueboolean trueboolean trueboolean trueboolean false

定期的にトークンに参加するアルゴリズム

定期的にトークンに参加する場合、crontab を使用して実装し、毎分呼び出します。 add メソッドはいくつかのトークンを追加します。 crontab の使用方法については、「Linux crontab スケジュールタスク実行コマンドの形式と詳細な例」を参照してください。

トークンバケット内のトークンが消費された場合、crontab の最小実行間隔は 1 分です。最初の数秒間はトークンが取得できず、残りの数十秒間はトークンを取得できず、ユーザーは長時間待たされてしまいます。

トークンを追加するアルゴリズムを最適化し、1 分以内に数秒ごとに複数のトークンを追加することで、1 分以内に毎回トークンを取得できるようになります。

crontab によって呼び出されるトークン追加プログラムは次のとおりで、1 秒あたり 3 つのトークンを自動的に追加します。

<?php/**
 * 定时任务加入令牌
 */require &#39;TrafficShaper.class.php&#39;;// redis连接设定$config = array(    &#39;host&#39; => &#39;localhost&#39;,    &#39;port&#39; => 6379,    &#39;index&#39; => 0,    &#39;auth&#39; => &#39;&#39;,    &#39;timeout&#39; => 1,    &#39;reserved&#39; => NULL,    &#39;retry_interval&#39; => 100,
);// 令牌桶容器$queue = &#39;mycontainer&#39;;// 最大令牌数$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 &#39;[&#39;.date(&#39;Y-m-d H:i:s&#39;).&#39;] add token num:&#39;.$add_num.PHP_EOL;
    sleep($time_step);
}?>
シミュレーション消費プログラムは次のとおりで、1 秒あたり 2 ~ 8 個のトークンを消費します。

<?php/**
 * 模拟用户访问消耗令牌,每段时间间隔消耗若干令牌
 */require &#39;TrafficShaper.class.php&#39;;// redis连接设定$config = array(    &#39;host&#39; => &#39;localhost&#39;,    &#39;port&#39; => 6379,    &#39;index&#39; => 0,    &#39;auth&#39; => &#39;&#39;,    &#39;timeout&#39; => 1,    &#39;reserved&#39; => NULL,    &#39;retry_interval&#39; => 100,
);// 令牌桶容器$queue = &#39;mycontainer&#39;;// 最大令牌数$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 &#39;[&#39;.date(&#39;Y-m-d H:i:s&#39;).&#39;] consume token:&#39;.($status? &#39;true&#39; : &#39;false&#39;).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回以降は消費トークンが大きくなります。参加トークンの枚数を超えるとアクセスが制限されます。

この記事では、トークン バケット アルゴリズムを使用して Redis に基づいたトラフィック制御を実装する PHP の関連コンテンツについて説明します。その他の関連コンテンツについては、PHP の中国語 Web サイトを参照してください。

関連する推奨事項:

PHP を使用してロゴ付きの QR コード クラスを作成する方法



mysql によるテーブル パーティションの再構築と保持の詳細な説明data メソッド


php json_encode がオブジェクトのプライベート属性をサポートしていないことについての説明

以上がRedis に基づくトラフィック制御を実装するためにトークン バケット アルゴリズムを使用して PHP の関連コンテンツを説明するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。