漏桶算法-php實現

漏桶算法-php實現

1,概覽

最近研究nginx的限流,limit_req_zone。
其功能就是限制大訪問量下的請求數量,防止服務器故障。

核心邏輯就是:
    1,給nginx配置一個處理請求速率。比如每秒處理5個請求。
    2,大訪問量下沒有處理到的請求進行排隊等待。
    3,給排隊的請求配置一個長度,超過了長度的請求直接返回錯誤 。比如設置隊列長度爲5,有5個請求正在排隊的情況下,
       下一個請求直接返回錯誤。

比較感興趣它的實現,查閱資料發現利用了漏桶算法。就順便帶着學習一下。
    漏桶算法的原理:

        漏桶有一定的容量,給漏桶注水,當單位時間內注入水量大於流出水量,漏桶內積累的水就會越來越多,直到溢出。

        就好比大批量請求訪問nginx相當於注水,nginx根據配置按照固定速率處理請求當做排水。
        漏桶容量就好比配置給nginx的隊列長度。當漏桶發生溢出,則禁止請求進入,直接返回錯誤。

2,實現

/**
 * [leaky php實現漏桶算法]
 * @Author   [NiuShao   <[email protected]> <qq:370574131>]
 * @DateTime 2020-06-26
 * @param    [type]     $contain            [int 桶的總容量]
 * @param    [type]     $addNum             [int 每次注入桶中的水量]
 * @param    [type]     $leakRate           [int 桶中漏水的速率,秒爲單位。例如2/s,3/s]
 * @param    integer    &$water             [int 當前水量,默認爲0]
 * @param    integer    &$preTime           [int 時間戳,記錄的上次漏水時間]
 * @return   [type]                         [bool,返回可否繼續注入true/false]
 */
function leaky($contain,$addNum,$leakRate,&$water=0,&$preTime=0)
{
    //參數賦值
    //首次進入默認當前水量爲0
    $water = empty($water) ? 0 : $water;
    //首次進入默認上次漏水時間爲當前時間
    $preTime = empty($water) ? time() : $preTime;
    $curTime = time();
    //上次結束到本次開始,流出去的水
    $leakWater = ($curTime-$preTime)*$leakRate;
    //上次結束時候的水量減去流出去的水,也就是本次初始水量
    $water = $water-$leakWater;
    //水量不可能爲負,漏出大於進入則水量爲0
    $water = ( $water>=0 ) ? $water : 0 ;
    //更新本次漏完水的時間
    $preTime = $curTime;
    //水小於總容量則可注入,否則不可注入
    if( ($water+$addNum) <= $contain ){
        $water += $addNum;
        return true;
    }else{
        return false;
    }

}

/**
 * 測試
 * @var integer
 */
for($i=0;$i<500;$i++){
    $res = leaky(50,1,5,$water,$timeStamp);
    var_dump($res);
    usleep(50000);
}

3,說明:

上面的漏桶算法更加的一般化了,容器總量,注水量,排水量都可以隨機設置。
爲了完全使用php實現,時間參數$preTime和當前水量$water都利用了php的引用賦值。作爲全局變量。
測試過程利用率循環機制給漏桶注水。

在實際生產環境下如果要用php代碼做限流,容器總量,注水排水都不能爲小數。
並且對時間參數和當前水量建議用redis緩存或者文件緩存來進行保存。
因爲(nginx+php-fpm)架構下,每次請求都是獨立的,所有變量都會被釋放。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章