真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

PHP怎么實現(xiàn)令牌桶限流

小編給大家分享一下PHP怎么實現(xiàn)令牌桶限流,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

目前成都創(chuàng)新互聯(lián)已為上千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、綿陽服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計、麻栗坡網(wǎng)站維護(hù)等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

PHP實現(xiàn)令牌桶限流的方法:1、設(shè)有一個令牌桶,桶內(nèi)存放令牌;2、每次訪問從桶內(nèi)取走一個令牌;3、根據(jù)實際情況,每隔一段時間放入若干個令牌或直接補(bǔ)滿令牌桶即可。

本文操作環(huán)境:Windows7系統(tǒng)、PHP7.1、Dell G3電腦。

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

每當(dāng)國內(nèi)長假期或重要節(jié)日時,國內(nèi)的景區(qū)或地鐵都會人山人海,導(dǎo)致負(fù)載過大,部分則會采用限流措施,限制進(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)入一個人,N+1,當(dāng)N = M時,則不允許進(jìn)入
每離開一個人,N-1,當(dāng)N < M時,可允許進(jìn)入

系統(tǒng)在運行過程中,如遇上某些活動,訪問的人數(shù)會在一瞬間內(nèi)爆增,導(dǎo)致服務(wù)器瞬間壓力飆升,使系統(tǒng)超負(fù)荷工作。

當(dāng)然我們可以增加服務(wù)器去分擔(dān)壓力,首先增加服務(wù)器也需要一定的時間去配置,而且因為某一個活動而增加服務(wù)器,活動結(jié)束后這些服務(wù)器資源就浪費了。

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

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

令牌桶算法

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

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

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

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

_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);        // 計算最大可加入的令牌數(shù)量,不能超過最大令牌數(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:

 'localhost',
    'port' => 6379,
    'index' => 0,
    'auth' => '',
    'timeout' => 1,
    'reserved' => NULL,
    'retry_interval' => 100,
);

// 令牌桶容器
$queue = 'mycontainer';

// 最大令牌數(shù)
$max = 5;

// 創(chuàng)建TrafficShaper對象
$oTrafficShaper = new TrafficShaper($config, $queue, $max);

// 重設(shè)令牌桶,填滿令牌
$oTrafficShaper->reset();

// 循環(huán)獲取令牌,令牌桶內(nèi)只有5個令牌,因此最后3次獲取失敗
for($i=0; $i<8; $i++){
    var_dump($oTrafficShaper->get());
}

// 加入10個令牌,最大令牌為5,因此只能加入5個
$add_num = $oTrafficShaper->add(10);

var_dump($add_num);

// 循環(huán)獲取令牌,令牌桶內(nèi)只有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實現(xiàn),每分鐘調(diào)用add方法加入若干令牌。

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

我們可以優(yōu)化加入令牌的算法,改為一分鐘內(nèi)每若干秒加入若干令牌,這樣可以保證一分鐘內(nèi)每段時間都有機(jī)會能獲取到令牌。
 
crontab調(diào)用的加入令牌程序如下,每秒自動加入3個令牌。

 'localhost',
    'port' => 6379,
    'index' => 0,
    'auth' => '',
    'timeout' => 1,
    'reserved' => NULL,
    'retry_interval' => 100,
);

// 令牌桶容器
$queue = 'mycontainer';

// 最大令牌數(shù)
$max = 10;

// 每次時間間隔加入的令牌數(shù)
$token_num = 3;

// 時間間隔,最好是能被60整除的數(shù),保證覆蓋每一分鐘內(nèi)所有的時間
$time_step = 1;

// 執(zhí)行次數(shù)
$exec_num = (int)(60/$time_step);

// 創(chuàng)建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個令牌。

 'localhost',
    'port' => 6379,
    'index' => 0,
    'auth' => '',
    'timeout' => 1,
    'reserved' => NULL,
    'retry_interval' => 100,
);

// 令牌桶容器
$queue = 'mycontainer';

// 最大令牌數(shù)
$max = 10;

// 每次時間間隔隨機(jī)消耗的令牌數(shù)量范圍
$consume_token_range = array(2, 8);

// 時間間隔
$time_step = 1;

// 創(chuàng)建TrafficShaper對象
$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è)置定時任務(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

因令牌桶一開始是滿的(最大令牌數(shù)10),所以之前的10次都能獲取到令牌,10次之后則會根據(jù)消耗的令牌大于加入令牌數(shù)時,限制訪問。

以上是“PHP怎么實現(xiàn)令牌桶限流”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


分享標(biāo)題:PHP怎么實現(xiàn)令牌桶限流
本文URL:http://weahome.cn/article/jideep.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部