使用redis把隊列的異步返回改成同步 - 隊列使用

web編程開發中,會遇到資源爭用的情況。舉例:

有多個商品,商品搶單,每個商品都有數量限制。

但凡遇到此類問題,自古以來,就有兩種解決方式:1、使用鎖,2、使用隊列。
使用任意一個就可以。

使用隊列的方式最爲簡單,不考慮加鎖。也無需使用數據庫的鎖。

把所有的請求都放入隊列,然後把隊列處理的結果返回給客戶端。每次都查詢商品的剩餘數量是否爲0,爲0就拒絕請求。

如果商品太多,可以按商品大類分成多個隊列。這樣處理速度快些。

現在的問題是:隊列是異步返回的,怎麼辦呢?

構思場景,[size=large][b]進程A處理web請求(會同時有多個類似A的進程出現),進程B是隊列,進程C是監聽隊列的守護進程。[/b][/size]
簡單的做法是:A把請求放入隊列,然後進程C處理好直接異步通知客戶端,但這得有nodejs之類的長連接幫助。因爲要推送。

所以使用如下方案解決:
[size=x-large]使用redis把隊列的異步返回改成同步[/size]
[size=large]
1、添加redis守護進程D。[/size]
[b]新的場景:進程A處理web請求(會同時有多個類似A的進程出現),進程B是隊列,進程C是監聽隊列的守護進程。進程D是redis。[/b]

[size=large]2、web請求進程A:[/size]
創建一個隨機數random。
把處理消息發給隊列,但是把random加入到消息裏。
使用 $result = $redis->blPop(random, 30);// 30秒是等待時間,
$redis->delete(random); // 取出消息後,這個鍵就沒用了。
BLPOP是列表的阻塞式(blocking)彈出原語。

它是LPOP命令的阻塞版本,當給定列表內沒有任何元素可供彈出的時候,連接將被BLPOP命令阻塞,直到等待超時或發現可彈出元素爲止。

然後只要從$result中獲取進程C的返回即可。

[size=large]3、守護進程C:[/size]
把rendom從消息中取出,處理整條消息,得到結果。
然後把結果放到以random爲鍵名稱的redis的列表裏。即可。

$redis->lPush(random, '處理結果');//這句話執行完後,進程A的blPop方法會立刻返回!

[size=large]4、缺點:[/size]
此方案沒什麼缺點,只有隊列本身的缺點,就是如果併發請求太多,處理不過來,則客戶端需要等。
解決方案就是添加多個隊列,添加多個守護進程處理隊列,守護進程和隊列也可以分佈在不同的服務器。

[size=large]5、優點:[/size]
[b]超級簡單,redis很棒。[/b]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章