處理高併發 IO瓶頸解決紅包程式

SmallForest發表於2019-02-16

解決高併發 io瓶頸解決紅包程式

本程式模擬的紅包抽獎模式。總金額100元,隨機使用者獲得1-10元的紅包,直到紅包分發完。
redis中luckMoneyMax需要提前設定

$r->set(`luckMoneyMax` , 100);

正文

    /**
     * 隨機獲取紅包
     * 總金額100元
     * 每次紅包大小[1,10]
     */
    public function luckMoney()
    {
        $r = new Redis();
        $r->pconnect(`127.0.0.1`,`6379`);
        $r->select(1);

        $lock_key = `lockkey`;
        while(true){

            $lock_timout = time()+3+1;
            //4秒超時 一個鎖超過4s還沒釋放 說明得到鎖的執行緒掛了 其他執行緒需要競爭釋放鎖 再得到鎖
            $get_lock = $r->setnx($lock_key,$lock_timout);


            //得到鎖的條件 setnx返回值為真 超時並且getSet保證了不會多個程式去釋放鎖
            $now = time();

            if($get_lock || ( ($now > $r->get($lock_key)) && ($now > $r->getSet($lock_key , $lock_timout)) ) ){
                echo `去抽獎!<br>`;
                break;//去抽獎
            }

        }
        $luckMoneyMax = $r->get(`luckMoneyMax`);
        if($luckMoneyMax <= 0){
            

            echo `獎金池空了!`;
            if((time() < $lock_timout) && $r->del($lock_key)){
                echo `<br>毫秒時間:`.$this->msectime().`釋放鎖成功`;
            }
            return;
        }elseif($luckMoneyMax <= 1){
            $redBag = $luckMoneyMax;
            $r->set(`luckMoneyMax` , 0);
            $data_arr = [
                `redBag`=>$redBag,
                `mstime`=>$this->msectime()
            ];
            $r->lpush("redBag-list", serialize($data_arr));

            echo `恭喜中獎`.$redBag;

            if((time() < $lock_timout) && $r->del($lock_key)){
                echo `<br>毫秒時間:`.$this->msectime().`釋放鎖成功`;
            }
            return;
        }
        //1-10 十元整數
        $redBag = rand(1,10);
        $tmp_money = $luckMoneyMax-$redBag;
        if($tmp_money < 0){
            $redBag = $luckMoneyMax;
            $tmp_money=0;
        }
        $r->set(`luckMoneyMax` , $tmp_money);

        $data_arr = [
            `redBag`=>$redBag,
            `mstime`=>$this->msectime()
        ];
        $r->lpush("redBag-list", serialize($data_arr));
        echo `恭喜中獎`.$redBag.`元`;
        if((time() < $lock_timout) && $r->del($lock_key)){
            echo `<br>毫秒時間:`.$this->msectime().`釋放鎖成功`;
        }

    }

    /**
     * 毫秒級
     * @return float
     */
    public function msectime() {
        list($msec, $sec) = explode(` `, microtime());
        $msectime =  (float)sprintf(`%.0f`, (floatval($msec) + floatval($sec)) * 1000);
        return $msectime;
    }

swoole多執行緒測試

<?php
echo "start:".date("Y-m-d H:i:s").PHP_EOL;

for ($i=0 ; $i<100 ;$i++){
    $red_process = new swoole_process(`getMoney`,true);
    $red_process->start();
    echo PHP_EOL;//PHP_EOL換行的意思
    echo $red_process->read();
    echo PHP_EOL;
}

echo "end:".date("Y-m-d H:i:s").PHP_EOL;

function getMoney(swoole_process $worker)
{
    $content = getHTTPS(`http://example.com/index/index/luckMoney.html`);
    $worker->write($content);
}
function getHTTPS($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_REFERER, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}
日誌記錄結果

2s 100 次就抽取完畢

毫秒 紅包金額
毫秒時間1514386342125 紅包10元
毫秒時間1514386342106 紅包10元
毫秒時間1514386342086 紅包10元
毫秒時間1514386342066 紅包7元
毫秒時間1514386342046 紅包6元
毫秒時間1514386342026 紅包5元
毫秒時間1514386342007 紅包3元
毫秒時間1514386341988 紅包1元
毫秒時間1514386341968 紅包7元
毫秒時間1514386341950 紅包5元
毫秒時間1514386341931 紅包8元
毫秒時間1514386341913 紅包7元
毫秒時間1514386341894 紅包1元
毫秒時間1514386341875 紅包1元
毫秒時間1514386341856 紅包9元
毫秒時間1514386341836 紅包10元
合計 100元

推薦:
100萬個openid快速存入redis

相關文章