首頁  >  文章  >  資料庫  >  redis可以做訊息隊列嗎

redis可以做訊息隊列嗎

尚
原創
2019-07-05 15:31:483717瀏覽

redis可以做訊息隊列嗎

應用場景:

例如秒殺。瞬時大量寫入訂單到資料庫,導致資料庫無法及時回應。此時可以採用Redis做訊息佇列,把所有需要寫入的資料先寫入Redis訊息佇列中,然後同時在伺服器開啟php-cli進程循環讀取佇列中的數據,非同步寫入資料庫。使用redis做訊息佇列可能會出現訊息遺失的情況,因為沒有訊息接收的確認機制。大型程序,應該使用類似RabitMQ來做專業訊息佇列。

1、使用publish/subscribe方式作為訊息佇列

特點:一個訊息發布者(生產者),可以對應多個訊息訂閱者(消費者)。當訊息發佈到訊息佇列的時候,所有訊息訂閱者都可以收到訊息。適用於分散式訊息分發。 client以阻塞的方式等待publish端的訊息。多個消費者不能加快訊息消費速度。

訊息生產:

$params =json_encode(['x_uid' => $x_uid, 'phone' => $phone]);
$redis->publish('test',$params); //test表示发布的频道名字

訊息消費(php-cli模式執行):

$redis = new Redis(); $redis->pconnect('127.0.0.1'); //必须用pconnect长连接
//设置redis连接永远不超时。默认60s超时断开连接 $redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
 
$redis->subscribe(array('test'), 'callback'); //test表示频道名字,callback 回调函数名
functioncallback($redis, $chan, $msg){ //对收到的消息进行处理函数
$params = json_decode($msg,true);
....
}

pconnect和connect差異:

##connect:腳本結束後連接就釋放了。

pconnect:腳本結束後連線不釋放,連線保持在php-fpm進程中。

所以使用pconnect代替connect,可以減少頻繁建立redis連線的消耗。

2、使用list作為redis訊息佇列

特點:一個訊息生產者,對應一個訊息消費者。多位消費者可以加快訊息消費速度。

訊息生產:

$redis =newRedis();
$redis->connect('127.0.0.1'); 
//将需要写入数据库的数据全部push到队列(复杂数据可以先json编码成字符串)
$list = json_encode(['x_uid' => $x_uid, 'phone' => $phone, 'goods_id' => $goodsId, 
'add_time' => time(), 'num_field' => $num_field]);
$redis->lpush('winer',$list);

注意:brpop消費資料如果沒有成功寫入資料庫,會導致資料遺失。強烈要求生產資料時,二次備份到redis或文件中。

訊息消費(php-cli模式運行):

注意:MySQL不主動關閉連線的情況下,一次連線最長八小時後自動中斷。

<?php
//链接数据库
$conn = mysqli_connect("localhost","root","root");
if(!$conn){
die("连接数据库失败:". mysqli_error());
}
mysqli_select_db($conn,"api");
//字符转换,读库
mysqli_query($conn,"set character set &#39;utf8&#39;");
//写库
mysqli_query($conn,"set names &#39;utf8&#39;");
 
//连接本地的 Redis 服务
$redis =newRedis();
$redis->connect(&#39;127.0.0.1&#39;,6379);
//设置redis连接永远不超时。默认60s超时断开连接
$redis->setOption(Redis::OPT_READ_TIMEOUT,-1);
echo &#39;Listening...&#39;;
$i =1;
while(true){
$data = $redis->brpop(&#39;winer&#39;,0); // 0表示没有接收到参数的情况下,永远不超时断开
$info = json_decode($data[1],true);
$x_uid = $info[&#39;x_uid&#39;];
$phone = $info[&#39;phone&#39;];
$goods_id = $info[&#39;goods_id&#39;];
$add_time = $info[&#39;add_time&#39;];
$num_field = $info[&#39;num_field&#39;];
//将数组写入数据库、订单
$sql = "insert into hd_hengda11_order (`x_uid`,`phone`,`goods_id`,`add_time`) 
values ($x_uid,$phone,$goods_id,$add_time)"
$re = mysqli_query($conn,$sql);

echo $i.&#39;_ok||&#39;;
$i++;
}
?>

其他:

秒殺場景防止商品超賣:

#1、資料庫中設定商品數量為無符號型,即不允許負數。當更新商品數量到負數時,返回false。

2、商品數量存在Redis的list隊列中,每次搶購就pop刪除一個元素出隊列。

//存放商品数量的队列
for($j =1; $j <=10; $j++){ /设置商品数量为10
$re =Redis::lpush(gooods_count,1);
}

判斷商品數量邏輯

$count=Redis::lpop(&#39;gooods_count&#39;);
//$count = Redis::llen(&#39;gooods_count&#39;); //llen判断队列长度
if(!$count){
return&#39;已经抢光了哦&#39;;
}

更多Redis相關知識,請造訪

Redis使用教學欄位!

以上是redis可以做訊息隊列嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn