麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 學(xué)院 > 邏輯算法 > 正文

php 基于redis使用令牌桶算法實(shí)現(xiàn)流量控制

2020-03-22 18:58:26
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
本文介紹php基于redis,使用令牌桶算法,實(shí)現(xiàn)訪問(wèn)流量的控制,提供完整算法說(shuō)明及演示實(shí)例,方便大家學(xué)習(xí)使用。
每當(dāng)國(guó)內(nèi)長(zhǎng)假期或重要節(jié)日時(shí),國(guó)內(nèi)的景區(qū)或地鐵都會(huì)人山人海,導(dǎo)致負(fù)載過(guò)大,部分則會(huì)采用限流措施,限制進(jìn)入的人數(shù),當(dāng)區(qū)內(nèi)人數(shù)降低到一定值,再允許進(jìn)入。

例如:
區(qū)內(nèi)最大允許人數(shù)為 M
區(qū)內(nèi)當(dāng)前人數(shù)為 N
每進(jìn)入一個(gè)人,N+1,當(dāng)N = M時(shí),則不允許進(jìn)入
每離開(kāi)一個(gè)人,N-1,當(dāng)N < M時(shí),可允許進(jìn)入
系統(tǒng)在運(yùn)行過(guò)程中,如遇上某些活動(dòng),訪問(wèn)的人數(shù)會(huì)在一瞬間內(nèi)爆增,導(dǎo)致服務(wù)器瞬間壓力飆升,使系統(tǒng)超負(fù)荷工作。

當(dāng)然我們可以增加服務(wù)器去分擔(dān)壓力,首先增加服務(wù)器也需要一定的時(shí)間去配置,而且因?yàn)槟骋粋€(gè)活動(dòng)而增加服務(wù)器,活動(dòng)結(jié)束后這些服務(wù)器資源就浪費(fèi)了。

因此我們可以根據(jù)業(yè)務(wù)類型,先使用限流的方式去減輕服務(wù)器壓力。

與景區(qū)限流不同,系統(tǒng)的訪問(wèn)到結(jié)束的時(shí)間非常短,因此我們只需要知道每個(gè)訪問(wèn)持續(xù)的平均時(shí)間,設(shè)定最多同時(shí)訪問(wèn)的人數(shù)即可。

令牌桶算法

1.首先設(shè)有一個(gè)令牌桶,桶內(nèi)存放令牌,一開(kāi)始令牌桶內(nèi)的令牌是滿的(桶內(nèi)令牌的數(shù)量可根據(jù)服務(wù)器情況設(shè)定)。

2.每次訪問(wèn)從桶內(nèi)取走一個(gè)令牌,當(dāng)桶內(nèi)令牌為0,則不允許再訪問(wèn)。

3.每隔一段時(shí)間,再放入令牌,最多使桶內(nèi)令牌滿額。(可以根據(jù)實(shí)際情況,每隔一段時(shí)間放入若干個(gè)令牌,或直接補(bǔ)滿令牌桶)

我們可以使用redis的隊(duì)列作為令牌桶容器使用,使用lPush(入隊(duì)),rPop(出隊(duì)),實(shí)現(xiàn)令牌加入與消耗的操作。

TrafficShaper.html' target='_blank'>class.php

<?php/** * PHP基于Redis使用令牌桶算法實(shí)現(xiàn)流量控制 * Date:    2018-02-23 * Author:  fdipzone * Version: 1.0 * * Descripton: * php基于Redis使用令牌桶算法實(shí)現(xiàn)流量控制,使用redis的隊(duì)列作為令牌桶容器,入隊(duì)(lPush)出隊(duì)(rPop)作為令牌的加入與消耗操作。 * * Func: * public  add     加入令牌 * public  get     獲取令牌 * public  reset   重設(shè)令牌桶 * private connect 創(chuàng)建redis連接 */class TrafficShaper{ // class start    private $_config; // redis設(shè)定    private $_redis;  // redis對(duì)象    private $_queue;  // 令牌桶    private $_max;    // 最大令牌數(shù)    /**     * 初始化     * @param Array $config redis連接設(shè)定     */    public function __construct($config, $queue, $max){        $this->_config = $config;        $this->_queue = $queue;        $this->_max = $max;        $this->_redis = $this->connect();    }    /**     * 加入令牌     * @param  Int $num 加入的令牌數(shù)量     * @return Int 加入的數(shù)量     */    public function add($num=0){        // 當(dāng)前剩余令牌數(shù)        $curnum = intval($this->_redis->lSize($this->_queue));        // 最大令牌數(shù)        $maxnum = intval($this->_max);        // 計(jì)算最大可加入的令牌數(shù)量,不能超過(guò)最大令牌數(shù)        $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;    }    /**     * 重設(shè)令牌桶,填滿令牌     */    public function reset(){        $this->_redis->delete($this->_queue);        $this->add($this->_max);    }    /**     * 創(chuàng)建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?>

demo:

<?php/** * 演示令牌加入與消耗 */require 'TrafficShaper.class.php';// redis連接設(shè)定$config = array(    'host' => 'localhost',    'port' => 6379,    'index' => 0,    'auth' => '',    'timeout' => 1,    'reserved' => NULL,    'retry_interval' => 100,);// 令牌桶容器$queue = 'mycontainer';// 最大令牌數(shù)$max = 5;// 創(chuàng)建TrafficShaper對(duì)象$oTrafficShaper = new TrafficShaper($config, $queue, $max);// 重設(shè)令牌桶,填滿令牌$oTrafficShaper->reset();// 循環(huán)獲取令牌,令牌桶內(nèi)只有5個(gè)令牌,因此最后3次獲取失敗for($i=0; $i<8; $i++){    var_dump($oTrafficShaper->get());}// 加入10個(gè)令牌,最大令牌為5,因此只能加入5個(gè)$add_num = $oTrafficShaper->add(10);var_dump($add_num);// 循環(huán)獲取令牌,令牌桶內(nèi)只有5個(gè)令牌,因此最后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實(shí)現(xiàn),每分鐘調(diào)用add方法加入若干令牌。crontab的使用可以參考:《Linux crontab定時(shí)執(zhí)行任務(wù) 命令格式與詳細(xì)例子》

crontab最小的執(zhí)行間隔為1分鐘,如果令牌桶內(nèi)的令牌在前幾秒就已經(jīng)被消耗完,那么剩下的幾十秒時(shí)間內(nèi),都獲取不到令牌,導(dǎo)致用戶等待時(shí)間較長(zhǎng)。

我們可以優(yōu)化加入令牌的算法,改為一分鐘內(nèi)每若干秒加入若干令牌,這樣可以保證一分鐘內(nèi)每段時(shí)間都有機(jī)會(huì)能獲取到令牌。

crontab調(diào)用的加入令牌程序如下,每秒自動(dòng)加入3個(gè)令牌。

<?php/** * 定時(shí)任務(wù)加入令牌 */require 'TrafficShaper.class.php';// redis連接設(shè)定$config = array(    'host' => 'localhost',    'port' => 6379,    'index' => 0,    'auth' => '',    'timeout' => 1,    'reserved' => NULL,    'retry_interval' => 100,);// 令牌桶容器$queue = 'mycontainer';// 最大令牌數(shù)$max = 10;// 每次時(shí)間間隔加入的令牌數(shù)$token_num = 3;// 時(shí)間間隔,最好是能被60整除的數(shù),保證覆蓋每一分鐘內(nèi)所有的時(shí)間$time_step = 1;// 執(zhí)行次數(shù)$exec_num = (int)(60/$time_step);// 創(chuàng)建TrafficShaper對(duì)象$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個(gè)令牌。

<?php/** * 模擬用戶訪問(wèn)消耗令牌,每段時(shí)間間隔消耗若干令牌 */require 'TrafficShaper.class.php';// redis連接設(shè)定$config = array(    'host' => 'localhost',    'port' => 6379,    'index' => 0,    'auth' => '',    'timeout' => 1,    'reserved' => NULL,    'retry_interval' => 100,);// 令牌桶容器$queue = 'mycontainer';// 最大令牌數(shù)$max = 10;// 每次時(shí)間間隔隨機(jī)消耗的令牌數(shù)量范圍$consume_token_range = array(2, 8);// 時(shí)間間隔$time_step = 1;// 創(chuàng)建TrafficShaper對(duì)象$oTrafficShaper = new TrafficShaper($config, $queue, $max);// 重設(shè)令牌桶,填滿令牌$oTrafficShaper->reset();// 執(zhí)行令牌消耗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);}?>

演示

設(shè)置定時(shí)任務(wù),每分鐘執(zhí)行一次

* * * * * php /程序的路徑/cron_add.php >> /tmp/cron_add.log

執(zhí)行模擬消耗

php consume_demo.php

執(zhí)行結(jié)果:

[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

因令牌桶一開(kāi)始是滿的(最大令牌數(shù)10),所以之前的10次都能獲取到令牌,10次之后則會(huì)根據(jù)消耗的令牌大于加入令牌數(shù)時(shí),限制訪問(wèn)。
本文講解了php 基于redis使用令牌桶算法實(shí)現(xiàn)流量控制 ,更多相關(guān)內(nèi)容請(qǐng)關(guān)注 。

相關(guān)推薦:

Redis主從同步,讀寫(xiě)分離設(shè)置 的相關(guān)操作

介紹mysql重建表分區(qū)并保留數(shù)據(jù)的方法

PHP生成唯一RequestID類的相關(guān)內(nèi)容

以上就是php 基于redis使用令牌桶算法實(shí)現(xiàn)流量控制的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注 其它相關(guān)文章!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 国产亚洲精品综合一区91555 | 91精品国产综合久久久欧美 | 亚洲骚妻 | 毛片在哪里看 | 国产一区在线观看视频 | 亚洲一区二区三区在线看 | 亚洲欧美一区二区三区在线观看 | 久久华人 | 羞羞的动漫在线观看 | 97人操 | 久久精品亚洲成在人线av网址 | 极品国产91在线网站 | 91在线看黄 | 轻点插视频 | 蜜桃视频在线播放 | 欧美成人一区二区三区 | 午夜激情视频免费 | 国产成人精品网站 | 久久出精品 | 国产1区2区3区中文字幕 | 一级做受毛片免费大片 | pornoⅹxxxxhd麻豆 | 日韩av成人 | 国产精品爱久久久久久久 | 国产一级毛片a | 九九热在线免费观看视频 | 免费久久久久久久 | 国产一区网址 | 人成免费a级毛片 | 久久精品亚洲精品国产欧美kt∨ | 亚洲一区二区三区在线看 | 91情侣在线偷精品国产 | 欧美三日本三级少妇三级99观看视频 | 一级全毛片 | 黄色毛片一级 | 国产91在线播放九色 | 亚洲自拍第二页 | 在线播放免费视频 | 国产精品爆操 | 免费黄色小视频网站 | 亚洲少妇诱惑 |