Redis應用-異步消息隊列與延時隊列

系列文章redis

異步消息隊列

說道消息隊列,你確定會想到KafkaRabbitmq等消息中間件,這些專業的消息中間件提供了不少功能特性,固然他的部署使用維護都是比較麻煩的。若是你對消息隊列沒那麼高要求,想要輕量級的,使用Redis就沒錯啦。bash

Redis經過list數據結構來實現消息隊列.主要使用到以下命令:服務器

  • lpush和rpush入隊列
  • lpop和rpop出隊列
  • blpop和brpop阻塞式出隊列

廢話補很少說上代碼:微信

$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

  • 訂單下單後超過一小時用戶未支付,須要關閉訂單
  • 訂單的評論若是7天未評價,系統須要自動產生一條評論

這個時候咱們就須要用到延時隊列了,顧名思義就是須要延遲一段時間後執行。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 進行爭搶,那些沒搶到的進程都是白取了一次任務,這是浪費。解決辦法:將 zrangebyscorezrem使用lua腳本進行原子化操做,這樣多個進程之間爭搶任務時就不會出現這種浪費了。

本文亦在微信公衆號【小道資訊】發佈,歡迎掃碼關注!

相關文章
相關標籤/搜索