溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

redis能不能用來做消息隊(duì)列

發(fā)布時間:2020-11-16 11:40:46 來源:億速云 閱讀:464 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章主要介紹了redis能不能用來做消息隊(duì)列,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

應(yīng)用場景:

例如秒殺。瞬時大量寫入訂單到數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫無法及時響應(yīng)。此時可以采用Redis做消息隊(duì)列,把所有需要寫入的數(shù)據(jù)先寫入Redis消息隊(duì)列中,然后同時在服務(wù)器開啟php-cli進(jìn)程循環(huán)讀取隊(duì)列中的數(shù)據(jù),異步寫入數(shù)據(jù)庫。使用redis做消息隊(duì)列可能會出現(xiàn)消息丟失的情況,因?yàn)闆]有消息接收的確認(rèn)機(jī)制。大型程序,應(yīng)該使用類似RabitMQ來做專業(yè)消息隊(duì)列。

1、使用publish/subscribe方式作為消息隊(duì)列

特點(diǎn):一個消息發(fā)布者(生產(chǎn)者),可以對應(yīng)多個消息訂閱者(消費(fèi)者)。當(dāng)消息發(fā)布到消息隊(duì)列的時候,所有消息訂閱者都可以收到消息。適用于分布式消息分發(fā)。client以阻塞的方式等待publish端的消息。多個消費(fèi)者不能加快消息消費(fèi)速度。

消息生產(chǎn):

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

消息消費(fèi)(php-cli模式運(yùn)行):

$redis = new Redis(); $redis->pconnect('127.0.0.1'); //必須用pconnect長連接
//設(shè)置redis連接永遠(yuǎn)不超時。默認(rèn)60s超時斷開連接 $redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
 
$redis->subscribe(array('test'), 'callback'); //test表示頻道名字,callback 回調(diào)函數(shù)名
functioncallback($redis, $chan, $msg){ //對收到的消息進(jìn)行處理函數(shù)
$params = json_decode($msg,true);
....
}

pconnect和connect區(qū)別:

connect:腳本結(jié)束之后連接就釋放了。

pconnect:腳本結(jié)束之后連接不釋放,連接保持在php-fpm進(jìn)程中。

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

2、使用list作為redis消息隊(duì)列

特點(diǎn):一個消息生產(chǎn)者,對應(yīng)一個消息消費(fèi)者。多個消費(fèi)者可以加快消息消費(fèi)速度。

消息生產(chǎn):

$redis =newRedis();
$redis->connect('127.0.0.1'); 
//將需要寫入數(shù)據(jù)庫的數(shù)據(jù)全部push到隊(duì)列(復(fù)雜數(shù)據(jù)可以先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消費(fèi)數(shù)據(jù)如果沒有成功寫入數(shù)據(jù)庫,會導(dǎo)致數(shù)據(jù)丟失。強(qiáng)烈要求生產(chǎn)數(shù)據(jù)時,二次備份到redis或文件中。

消息消費(fèi)(php-cli模式運(yùn)行):

注意:MySQL不主動關(guān)閉連接的情況下,一次連接最長八小時后自動斷開。

<?php
//鏈接數(shù)據(jù)庫
$conn = mysqli_connect("localhost","root","root");
if(!$conn){
die("連接數(shù)據(jù)庫失敗:". mysqli_error());
}
mysqli_select_db($conn,"api");
//字符轉(zhuǎn)換,讀庫
mysqli_query($conn,"set character set 'utf8'");
//寫庫
mysqli_query($conn,"set names 'utf8'");
 
//連接本地的 Redis 服務(wù)
$redis =newRedis();
$redis->connect('127.0.0.1',6379);
//設(shè)置redis連接永遠(yuǎn)不超時。默認(rèn)60s超時斷開連接
$redis->setOption(Redis::OPT_READ_TIMEOUT,-1);
echo 'Listening...';
$i =1;
while(true){
$data = $redis->brpop('winer',0); // 0表示沒有接收到參數(shù)的情況下,永遠(yuǎn)不超時斷開
$info = json_decode($data[1],true);
$x_uid = $info['x_uid'];
$phone = $info['phone'];
$goods_id = $info['goods_id'];
$add_time = $info['add_time'];
$num_field = $info['num_field'];
//將數(shù)組寫入數(shù)據(jù)庫、訂單
$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.'_ok||';
$i++;
}
?>

其他:

秒殺場景防止商品超賣:

1、數(shù)據(jù)庫中設(shè)置商品數(shù)量為無符號型,即不允許負(fù)數(shù)。當(dāng)更新商品數(shù)量到負(fù)數(shù)時,返回false。

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

//存放商品數(shù)量的隊(duì)列
for($j =1; $j <=10; $j++){ /設(shè)置商品數(shù)量為10
$re =Redis::lpush(gooods_count,1);
}

判斷商品數(shù)量邏輯

$count=Redis::lpop('gooods_count');
//$count = Redis::llen('gooods_count'); //llen判斷隊(duì)列長度
if(!$count){
return'已經(jīng)搶光了哦';
}

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享redis能不能用來做消息隊(duì)列內(nèi)容對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,遇到問題就找億速云,詳細(xì)的解決方法等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI