系列文章redis
說道消息隊列,你確定會想到Kafka
、Rabbitmq
等消息中間件,這些專業的消息中間件提供了不少功能特性,固然他的部署使用維護都是比較麻煩的。若是你對消息隊列沒那麼高要求,想要輕量級的,使用Redis就沒錯啦。bash
Redis經過list
數據結構來實現消息隊列.主要使用到以下命令:服務器
廢話補很少說上代碼:微信
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
//發送消息
$redis->lPush($list, $value);
//消費消息
while (true) {
try {
$msg = $redis->rPop($list);
if (!$msg) {
sleep(1);
}
//業務處理
} catch (Exception $e) {
echo $e->getMessage();
}
}
複製代碼
上面代碼會有個問題若是隊列長時間是空的,那pop就不會不斷的循環,這樣會致使redis的QPS升高,影響性能。因此咱們使用sleep
來解決,當沒有消息的時候阻塞一段時間。但其實這樣還會帶來另外一個問題,就是sleep
會致使消息的處理延遲增長。這個問題咱們能夠經過blpop/brpop
來阻塞讀取隊列。數據結構
blpop/brpop
在隊列沒有數據的時候,會當即進入休眠狀態,一旦數據到來,則馬上醒過來。消息的延遲幾乎爲零。用blpop/brpop替代前面的lpop/rpop,就完美解決了上面的問題。異步
還有一個須要注意的點是咱們須要是用try/catch
來進行異常捕獲,若是一直阻塞在那裏,Redis服務器通常會主動斷開掉空連接,來減小閒置資源的佔用。分佈式
你是否在作電商項目的時候會遇到以下場景:post
這個時候咱們就須要用到延時隊列了,顧名思義就是須要延遲一段時間後執行。Redis可經過zset
來實現。咱們能夠將有序集合的value設置爲咱們的消息任務,把value的score設置爲消息的到期時間,而後輪詢獲取有序集合的中的到期消息進行處理。性能
實現代碼以下:ui
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->zAdd($delayQueue,$tts, $value);
while(true) {
try{
$msg = $redis->zRangeByScore($delayQueue,0,time(),0,1);
if($msg){
continue;
}
//刪除消息
$ok = $redis->zrem($delayQueue,$msg);
if($ok){
//業務處理
}
} catch(\Exception $e) {
}
}
複製代碼
這裏又產生了一個問題,同一個任務可能會被多個進程取到以後再使用 zrem 進行爭搶,那些沒搶到的進程都是白取了一次任務,這是浪費。解決辦法:將 zrangebyscore
和zrem
使用lua腳本進行原子化操做,這樣多個進程之間爭搶任務時就不會出現這種浪費了。
本文亦在微信公衆號【小道資訊】發佈,歡迎掃碼關注!