之前做過redis處理併發的,處理效率要比直接操作mysql快1一倍左右,但其實效率還是不高,雖然redis是很快,但因爲要經過nginx,單個nginx處理併發的能力也是有限的,所以這一塊的瓶頸是nginx的併發能力。
既然如此,我們就玩點花的,用PHP處理併發的最強工具,Swoole
Swoole是什麼?
Swoole的實際就是一個底層使用C實現的PHP協程框架,他使 PHP 開發人員可以編寫高性能高併發的 TCP、UDP、Unix Socket、HTTP、 WebSocket 等服務,而這次,我們用到的就是http服務器。
下面這個是我封裝好的一個Swoole類,只要裝好swoole和redis擴展就能用
<?php
class Swoole
{
function __construct()
{
$http = new swoole_http_server("0.0.0.0", 8888);
$http->on("start", function ($server)
{
echo "Swoole http server is started at http://wrsndm:8888\n";
});
$http->on("request", function ($request, $response)
{
$this->response = $response;
//防止Chrome請求2次的問題
if ($request->server['path_info'] == '/favicon.ico' || $request->server['request_uri'] == '/favicon.ico') {
$response->end();
return;
}
$response->header("Content-Type", "text/plain; charset=utf-8");//中文編碼
$method = $request->get['method'] ?? 'index';
$this->$method($request);
// $response->end("Hello World Rand Number is:" . rand(0, 100) . "\n");
});
//實例化Redis
$this->redis = new Redis();
$this->redis->connect('redis', '6379');//redis可改成自己的IP
//啓動swoole_http服務
$http->start();
}
public function index($request)
{
$this->response->end('剩餘庫存' . $this->redis->lLen('goods_list'));
}
public function redis_qianghuo($request){
//查詢庫存
if($this->redis->lLen('goods_list') == 0) {
//記錄失敗次數
while (true){
if(!$this->redis->set('fail_lock',1,['EX'=>5,'NX']))//拿鎖的權限,沒拿到則continue
continue;
$num = $this->redis->get('fail_num');
$this->redis->set('fail_num', $num+1);
$this->redis->del('fail_lock');//解鎖
break;
}
$this->ajaxReturn('商品已售完...');
}
$uid = $request->server['remote_port'];
//查詢是否重複購買
// if($this->redis->sIsMember('bought_list',$uid)) {
// //記錄重複購買次數
//// while (true){
//// if(!$this->redis->set('bought_lock',1,['EX'=>5,'NX']))//拿鎖的權限,沒拿到則continue
//// continue;
//// $num = $this->redis->get('bought_num');
//// $this->redis->set('bought_num', $num+1);
//// $this->redis->del('bought_lock');//解鎖
//// break;
//// }
// $this->ajaxReturn('你已經購買過了!');
// echo "已經購買過了\n";
// return;
// }
//商品出隊
$goods_id = $this->redis->rpop('goods_list');
//uid添加到已搶購名單,防止重複搶購
$this->redis->sAdd('bought_list',$uid);
$value = array(
'uid' => $uid,
'goods_id' => $goods_id,
'time' => time(),
);
//保存訂單信息
$this->redis->hSet('order_info',$uid,json_encode($value));
$this->ajaxReturn('購買成功。');
echo "購買成功\n";
}
private function ajaxReturn($info){
$this->response->end($info);
}
}
$swoole = new Swoole();
首先要啓動swoole_http服務器,只能使用cli模式啓動,成功會輸出下面這段文字
然後我們用ab進行1W次的併發測試
ab -c10 -n10000 localhost:8999/?method=redis_qianghuo
然後是Nginx服務器的併發測試
可以看到,swoole處理是6.9秒,且全部成功,nginx處理是18秒,而且有276個失敗請求(我之前測的,錯誤率還挺高),效率提升了差不多2倍,我用的最低配的阿里雲,所以處理能力不是很強,rps只有1400,到生產環境部署,併發能力會更加強勁!