7

解决高并发 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


SmallForest
239 声望12 粉丝

github: