解决高并发 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元 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。